You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C语言中如何获取字符串中首个正则匹配结果的指针?

问题

我正在自行实现grep工具,在结合正则表达式使用-o选项时遇到了问题。以下代码针对普通字符串匹配可以正常工作:

void do_o(char *pattern, char *line, flags options) {
  char *copy;
  char *temp;
  long unsigned int i;
  copy = line;
  if (options.v) {
    do_o_v(pattern, line, options);
  } 
  else {
      if (options.i) {
      while (copy && strcasestr(copy, pattern))
      {
        i = 0;
        temp = strcasestr(copy, pattern);
        while (i < strlen(pattern))
        {
          printf("%c", temp[i]);
          i++;
        }
        printf("\n");
        copy = strcasestr(copy, pattern) + strlen(pattern);
      }
    } else {
      while (copy && strstr(copy, pattern))
      {
        
        i = 0;
        temp = strstr(copy, pattern);
        while (i < strlen(pattern))
        {
          printf("%c", temp[i]);
          i++;
        }
        printf("\n");
        copy = strstr(copy, pattern) + strlen(pattern);
      }
    }
  }
}

但我需要针对正则表达式实现相同逻辑,因此需要一个类似strstr()或strcasestr()且支持正则的函数。搜索相关示例时,大多看到使用regexec()和regcomp()函数,但它们返回整数而非我需要的指针。请问如何获取字符串中首个正则匹配结果的指针?另外我需要纯C语言实现的方案。

解决方案

C标准库的regexec()虽然不直接返回匹配指针,但可以通过regmatch_t结构体获取匹配位置的偏移量,进而计算出匹配结果的指针。具体实现逻辑如下:

1. 编译正则表达式

用regcomp()编译正则模式,根据需求设置flags:

  • REG_EXTENDED:使用扩展正则表达式语法(和grep默认行为一致)
  • REG_ICASE:忽略大小写(对应grep的-i选项)
  • REG_NEWLINE:让^和$匹配换行符的开头/结尾,同时让.不匹配换行符

2. 获取匹配指针

调用regexec()时传入regmatch_t数组,该结构体的rm_so成员是匹配内容在字符串中的起始偏移量(从0开始),rm_eo是结束偏移量。通过当前字符串指针 + match[0].rm_so即可得到匹配结果的起始指针,匹配长度为match[0].rm_eo - match[0].rm_so。

3. 循环匹配(模拟原逻辑)

每次匹配完成后,从当前匹配的结束位置之后继续查找,直到无匹配结果为止。

适配正则的示例代码

#include <regex.h>

void do_o_regex(char *pattern, char *line, flags options) {
    regex_t reg;
    int ret;
    regmatch_t match[1]; // 只捕获整个匹配结果,对应-o选项
    char *current = line;
    size_t current_len = strlen(line);

    // 设置编译flags
    int cflags = REG_EXTENDED;
    if (options.i) {
        cflags |= REG_ICASE;
    }
    cflags |= REG_NEWLINE; // 对齐grep的换行处理逻辑

    // 编译正则表达式
    ret = regcomp(&reg, pattern, cflags);
    if (ret != 0) {
        char err_buf[1024];
        regerror(ret, &reg, err_buf, sizeof(err_buf));
        fprintf(stderr, "regex compile error: %s\n", err_buf);
        regfree(&reg);
        return;
    }

    if (options.v) {
        // 可自行实现-v选项的正则逻辑,此处暂略
        regfree(&reg);
        return;
    }

    // 循环匹配所有结果
    while (current_len > 0) {
        ret = regexec(&reg, current, 1, match, 0);
        if (ret != 0) {
            break; // 无更多匹配
        }

        // 计算匹配的起始指针和长度
        char *match_start = current + match[0].rm_so;
        size_t match_len = match[0].rm_eo - match[0].rm_so;

        // 输出匹配结果
        printf("%.*s\n", (int)match_len, match_start);

        // 移动到下一个匹配起始位置,避免死循环
        size_t skip = match[0].rm_eo;
        if (skip == 0) {
            skip = 1; // 匹配空字符串时强制跳过1个字符
        }
        current += skip;
        current_len -= skip;
    }

    // 释放正则资源
    regfree(&reg);
}

关键注意事项

  • 必须调用regfree()释放regex_t结构体,避免内存泄漏
  • 处理空匹配情况:当match[0].rm_eo == match[0].rm_so时,需手动跳过1个字符,防止死循环
  • 错误处理:regcomp()和regexec()的返回值需检查,用regerror()可获取可读错误信息

内容的提问来源于stack exchange,提问作者Liuba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 07:15:26