位置:首页 > C > c 正则表达式 regex.h匹配提取示例

c 正则表达式 regex.h匹配提取示例

时间:2026-08-10  |  作者:白桃企划师  |  阅读:0

本文聚焦Linux、macOS及其他类Unix系统提供的POSIX regex.h接口,介绍如何在C语言程序中完成正则模式编译、字符串匹配、捕获内容提取、错误诊断和资源释放,并说明Windows开发时可采用的PCRE2方案。

C语言中的POSIX正则表达式支持

ISO C标准库没有内置正则表达式模块。Linux、macOS及其他类Unix系统通常提供POSIX正则接口,使用时需要包含regex.h。其基本工作过程是先调用regcomp编译模式,再通过regexec匹配字符串,最后调用regfree释放编译结果。本文代码适用于提供POSIX regex.h的系统。Windows通常不原生提供这套接口:如果项目必须沿用regex.h,可选用经过维护的POSIX兼容环境或兼容库;如果需要原生跨平台方案,通常选择PCRE2,安装PCRE2开发库后包含pcre2.h,并依次使用pcre2_compile、pcre2_match、pcre2_get_ovector_pointer和pcre2_code_free。PCRE2的API和正则语法均不能与regex.h代码直接互换。

编译正则模式

regcomp用于把模式字符串编译到regex_t对象中。常用标志REG_EXTENDED表示采用扩展正则语法,可直接使用加号、问号和分组等结构;REG_ICASE表示忽略英文字母大小写;REG_NOSUB表示只判断是否匹配,不保存匹配位置。函数返回零表示编译成功,非零返回值应交给regerror转换为可读错误信息。只有编译成功后,才能把该对象传给regexec,也只有成功编译的对象才应调用regfree释放。

  • regex_t regex;
  • int result = regcomp(®ex, "^[0-9]+$", REG_EXTENDED);
  • result不为零时,使用regerror读取错误原因

执行匹配并提取内容

regexec负责在目标字符串中执行已经编译的模式。返回零代表匹配成功,返回REG_NOMATCH代表没有匹配,其余返回值表示执行错误,并可同样传给regerror生成可读诊断。如果需要提取完整匹配或捕获组,可以准备regmatch_t数组。matches[0]表示完整匹配,后续元素依次对应捕获组;rm_so是起始字节偏移,rm_eo是结束字节偏移。未参与匹配的可选分组通常以rm_so和rm_eo为-1表示,复制前必须检查。提取时按rm_eo-rm_so计算字节数,使用memcpy复制并在末尾添加字符串结束符。偏移量按字节计算,因此处理中文等多字节文本时,不能直接把它当作字符数量。

  • regmatch_t matches[2]可保存完整匹配和一个捕获分组
  • if (matches[1].rm_so != -1) {
      size_t len = (size_t)(matches[1].rm_eo - matches[1].rm_so);
      char group[64];
      if (len < sizeof group) {
        memcpy(group, text + matches[1].rm_so, len);
        group[len] = '';
      }
    }
  • 目标缓冲区至少需要匹配字节数加1字节;长度超出缓冲区时应拒绝复制或改为动态分配

完整可编译示例

下面的程序使用捕获组从字符串中提取数字,并完整区分编译失败、未匹配和执行失败。regcomp失败时,regex对象尚未成功编译,因此程序直接报告错误而不调用regfree;编译成功后,无论regexec结果如何,退出前都会调用regfree。Linux和macOS通常可直接使用系统提供的POSIX接口编译,无需额外链接正则库。

  • 代码:

    #include 
    #include 
    #include 
    #include 
    
    int main(void) {
        const char *pattern = "^ID:([0-9]+)$";
        const char *text = "ID:2026";
        regex_t regex;
        regmatch_t matches[2];
    
        int rc = regcomp(®ex, pattern, REG_EXTENDED);
        if (rc != 0) {
            size_t size = regerror(rc, ®ex, NULL, 0);
            char *message = malloc(size);
            if (message != NULL) {
                regerror(rc, ®ex, message, size);
                fprintf(stderr, "正则编译失败: %sn", message);
                free(message);
            } else {
                fprintf(stderr, "正则编译失败,且无法分配错误缓冲区n");
            }
            return 1;
        }
    
        rc = regexec(®ex, text, 2, matches, 0);
        if (rc == 0) {
            if (matches[1].rm_so == -1) {
                fprintf(stderr, "捕获组未参与匹配n");
                regfree(®ex);
                return 1;
            }
    
            size_t length = (size_t)(matches[1].rm_eo - matches[1].rm_so);
            char *value = malloc(length + 1);
            if (value == NULL) {
                fprintf(stderr, "无法分配提取缓冲区n");
                regfree(®ex);
                return 1;
            }
    
            memcpy(value, text + matches[1].rm_so, length);
            value[length] = '';
            printf("完整匹配: %.*sn",
                   (int)(matches[0].rm_eo - matches[0].rm_so),
                   text + matches[0].rm_so);
            printf("提取的数字: %sn", value);
            free(value);
        } else if (rc == REG_NOMATCH) {
            printf("字符串不匹配n");
        } else {
            size_t size = regerror(rc, ®ex, NULL, 0);
            char *message = malloc(size);
            if (message != NULL) {
                regerror(rc, ®ex, message, size);
                fprintf(stderr, "正则执行失败: %sn", message);
                free(message);
            } else {
                fprintf(stderr, "正则执行失败,且无法分配错误缓冲区n");
            }
            regfree(®ex);
            return 1;
        }
    
        regfree(®ex);
        return 0;
    }
  • Linux/macOS编译命令:cc -std=c11 -Wall -Wextra -pedantic regex_demo.c -o regex_demo
  • 运行命令:./regex_demo

常见问题与改进建议

C字符串中的反斜杠本身具有转义含义,所以正则模式需要反斜杠时,通常要在字符串字面量中写成两个反斜杠。POSIX扩展正则与PCRE2语法并不完全相同,不应直接照搬所有网络示例。频繁处理相同模式时,可以只编译一次并重复调用regexec,以减少开销;多线程共享编译对象前,则应结合具体实现文档确认使用方式。处理不可信文本时还要关注输入规模,避免复杂模式造成过高的匹配成本。Windows原生项目若选择PCRE2,需要按PCRE2文档安装并链接8位、16位或32位库中的一种;处理普通char字符串时通常选择8位库,并在包含pcre2.h前定义PCRE2_CODE_UNIT_WIDTH 8。

掌握编译、匹配、内容提取、错误诊断和资源释放后,就能在提供POSIX regex.h的系统中稳定使用正则表达式。Linux、macOS等类Unix平台可采用本文示例;Windows原生或需要统一跨平台语法的项目,应优先评估PCRE2,并按其独立API改写编译、匹配、提取和释放流程。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多