Contents
  1. 1. Regex in C
  2. 2. 编译模式
  3. 3. 执行匹配
    1. 3.1. 匹配结果
  4. 4. 错误信息收集
  5. 5. 释放空间
  6. 6. 例程
  7. 7. 总结

Regex in C

  正则表达式在处理文本方面十分强大,几乎稍微复杂一些的文本操作都会用到,而在python和java中使用regex都十分方便,其实Linux中的C也提供也标准库,使用也不会很复杂。遗憾的是功能较java和python的regex库要少,缺乏替换等功能,需要使用者自己去实现。
  在Linux下输入man regcomp就可以查看所有与regex相关的函数的说明了,以下是一些关键信息的摘要,如果使用中遇到问题请自行查阅manual。

编译模式

1
int regcomp(regex_t *preg, const char *regex, int cflags);

  regcomp用来编译文本regex生成匹配规则,执行结果保存在regex_t结构的preg参数中,执行成功时返回0。
  由于使用java,python较多,下意识地将C函数库与java、python类库比较,C语言中常常使用结构体来实现OOP语言中与对象类似的功能。但是C语言函数调用使用值传递,且结构体与数组的定义形式与普通变量相同,数据都保存在栈中,而不是堆中(java所有的对象和数组都是new操作建立的,保存于堆中),所以常常看到将指针作为参数传入函数,但实际担当的是传递结果的角色。

执行匹配

1
2
int regexec(const regex_t *preg, const char *string, size_t nmatch,
regmatch_t pmatch[], int eflags);

  regexec将匹配规则与目标文本进行匹配,并将匹配结果保存在regmatch_t的结构数组pmatch[]中。

匹配结果

  正regmatch_t的结构如下:

1
2
3
4
typedef struct {
regoff_t rm_so;
regoff_t rm_eo;
} regmatch_t;

  rm_so,rm_eo分别记录了匹配成功字段的起始(第一个匹配字符)和结束点(结尾的下一个字符)的偏移量。

  正模式中如果有分组存在,那么将以类似$&,$1,$2…的顺序将结果存储到regmatch_t数组中。

错误信息收集

  当compile或execute出错时,可以使用以下函数获取错误信息。

1
2
size_t regerror(int errcode, const regex_t *preg, char *errbuf,
size_t errbuf_size);

  正参数中需要提供错误码和一个字符数组缓存,返回错误信息的长度。

  正操作完成后,记得匹配模式的内存空间。

释放空间

1
void regfree(regex_t *preg);

例程

  下面用一个完整的例子进行学习和总结。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <stdio.h>
#include <stdlib.h>
#include <regex.h>
#include <sys/types.h>
#include <string.h>
#define MAX_ERROR_MSG 0x1000
int main() {
regex_t *r = malloc(sizeof(regex_t)); //分配编译后模式的存储空间
//regex_t *r; //使用这句代替上句是不行的,因为指针未初始化
char *text = "room 10, dorm 18."; //目标文本
char *regtxt = "[a-z]+ ([0-9]+)"; //模式
int status = regcomp(r, regtxt, REG_EXTENDED | REG_NEWLINE); //编译模式
if (status) { //处理可能的错误
char error_message[MAX_ERROR_MSG];
regerror(status, r, error_message, MAX_ERROR_MSG);
printf("Regex error compiling '%s': %s\n",
text, error_message);
return 1;
}
size_t nmatch = 2; //保存结果,每次匹配有两组$&,$1结果,分别是整体与子匹配
regmatch_t m[nmatch];
char *p = text;
while (1) { //连续匹配直到行尾
status = regexec(r, p, nmatch, m, 0); //匹配操作
if (status) { //判断结束或错误
char error_message[MAX_ERROR_MSG];
regerror(status, r, error_message, MAX_ERROR_MSG);
printf("Regex stop executing '%s': %s\n",
text, error_message);
return 1;
}
int i;
for (i = 0; i < nmatch; i++) { //打印结果,注意regmatch_t中保存的偏移信息
printf("%.*s, so = %d, eo = %d\n", m[i].rm_eo - m[i].rm_so, p + m[i].rm_so, m[i].rm_so, m[i].rm_eo);
}
p += m[0].rm_eo;
}
regfree(r); //释放空间
return 0;
}

总结

  总的来看C中的regex库使用流程与其它高级语言差别不大,但是结构体和指针的使用使得操作要麻烦一些。最后regex标准库提供的函数只有compile, execute, free再加上error四个操作,类似循环匹配、字符替代的功能,就需要自己在此基础上实现了。

Contents
  1. 1. Regex in C
  2. 2. 编译模式
  3. 3. 执行匹配
    1. 3.1. 匹配结果
  4. 4. 错误信息收集
  5. 5. 释放空间
  6. 6. 例程
  7. 7. 总结