pcre2的标准使用确实有点复杂,有没有办法包成一个函数呢?比如regex_match("regex", target_string, ...) 直接返回一个group结果?这是一个非常好的想法。封装 PCRE2 的底层细节,只暴露“输入正则和字符串,输出结果数组”的接口,会让业务代码清爽很多。
在 C 语言中,主要难点在于内存管理:函数内部提取出的字符串结果(Substring)需要申请内存,调用者用完后需要释放内存。为了解决这个问题,设计了一个结构体 RegexResult 来承载结果,并提供了一个配套的 free 函数。
#define PCRE2_CODE_UNIT_WIDTH 8
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pcre2.h>
typedef struct {
int count;
char **groups;
} RegexResult;
void free_regex_result(RegexResult *result) {
if (!result) return;
if (result->groups) {
for (int i = 0; i < result->count; i++) {
if (result->groups[i]) free(result->groups[i]);
}
free(result->groups);
}
free(result);
}
RegexResult* regex_match(const char *pattern_str, const char *subject_str) {
pcre2_code *re;
int errornumber;
PCRE2_SIZE erroroffset;
pcre2_match_data *match_data;
int rc;
PCRE2_SIZE *ovector;
re = pcre2_compile(
(PCRE2_SPTR)pattern_str, PCRE2_ZERO_TERMINATED,
0, &errornumber, &erroroffset, NULL);
if (re == NULL) {
fprintf(stderr, "Regex compile failed.\n");
return NULL;
}
match_data = pcre2_match_data_create_from_pattern(re, NULL);
rc = pcre2_match(
re, (PCRE2_SPTR)subject_str, strlen(subject_str),
0, 0, match_data, NULL);
if (rc < 0) {
pcre2_match_data_free(match_data);
pcre2_code_free(re);
return NULL;
}
RegexResult *result = (RegexResult*)malloc(sizeof(RegexResult));
result->count = rc;
result->groups = (char**)malloc(sizeof(char*) * rc);
ovector = pcre2_get_ovector_pointer(match_data);
for (int i = 0; i < rc; i++) {
PCRE2_SPTR substring_start = (PCRE2_SPTR)subject_str + ovector[2*i];
size_t substring_len = ovector[2*i+1] - ovector[2*i];
result->groups[i] = (char*)malloc(substring_len + 1);
memcpy(result->groups[i], substring_start, substring_len);
result->groups[i][substring_len] = '\0';
}
pcre2_match_data_free(match_data);
pcre2_code_free(re);
return result;
}
int main() {
const char *text = "Order #89757 placed on 2023-10-05 total $99.50";
const char *pattern = "Order #(\\d+) placed on (\\d{4}-\\d{2}-\\d{2}) total \\$([0-9.]+)";
printf("Text: %s\n", text);
RegexResult *res = regex_match(pattern, text);
if (res) {
printf("Match Success!\n");
if (res->count > 1) printf("Order ID: %s\n", res->groups[1]);
if (res->count > 2) printf("Date: %s\n", res->groups[2]);
if (res->count > 3) printf("Amount: %s\n", res->groups[3]);
free_regex_result(res);
} else {
printf("No match found.\n");
}
return 0;
}
编译运行
gcc easy_pcre2.c -o easy_pcre2 -lpcre2-8 -std=gnu99
./easy_pcre2
封装后的优点
像 Python 一样简单:主函数里不需要关心 compile、match_data、ovector 这些底层概念。
结果直接可用:返回的是标准的 C 字符串 (char *),可以直接拿去 strcmp、atoi 或者存入数据库,不用担心没有 \0 结尾的问题。
内存安全:提供了 free_regex_result 函数,一键清理所有申请的字符串内存。