C/C++正则表达式编程

导读:

  GNU/Linux有两套库可用于正则表达式编程:POSIX库和PCRE库。前者不需要单独安装,一般需求还是能满足的,速度稍慢些。后者是久负盛名的Perl正则表达式库,功能强大,匹配速度快,不过可能需要单独安装。

  POSIX库

  如何使用POSIX库的例子:

  #include

  #include

  #include

  char *get_regerror (int errcode, regex_t *compiled)

  {

  size_t length = regerror (errcode, compiled, NULL, 0);

  char *buffer = malloc(length);

  if (!buffer) return NULL;

  (void) regerror (errcode, compiled, buffer, length);

  return buffer;

  }

  int regtest(const char*pattern, const char* string)

  {

  regex_t reg;

  regmatch_t *subexprs = NULL;

  int ret;

  int i;

  if (0 != (ret=regcomp(?, pattern, REG_EXTENDED))) {

  char *buffer = get_regerror(ret, ?);

  if (buffer) {

  fprintf(stderr, "regcomp:[%d]%s/n", ret, buffer);

  free(buffer);

  }

  return -1;

  }

  subexprs = malloc((reg.re_nsub+1)*sizeof(regmatch_t));

  if (!subexprs) {

  fprintf(stderr, "error malloc subexprs/n");

  regfree(?);

  return -1;

  }

  if (0 != (ret=regexec(?, string, reg.re_nsub+1, subexprs, 0))) {

  char *buffer = get_regerror(ret, ?);

  if (buffer) {

  fprintf(stderr, "regexec:[%d]%s/n", ret, buffer);

  free(buffer);

  }

  

  regfree(?);

  return -1;

  }

  for (i = 0; i <= reg.re_nsub; i++) {

  printf("[%d]:", i);

  

  if (subexprs[i].rm_so == subexprs[i].rm_eo) {

  printf("[EMPTY SUBEXPR]/n");

  }

  else if (subexprs[i].rm_so == -1 ||

  subexprs[i].rm_eo == -1) {

  printf("[NO SUBEXPR]/n");

  }

  else {

  fwrite(string+subexprs[i].rm_so, 1,

  subexprs[i].rm_eo-subexprs[i].rm_so, stdout);

  printf("/n");

  }

  }

  regfree(?);

  if (subexprs) free(subexprs);

  return 0;

  }

  int main(int argc, char *argv[])

  {

  if (argc != 3) {

  fprintf(stderr, "Usage: regtest pattern string/n");

  return -1;

  }

  fprintf(stderr, "pattern:%s/n", argv[1]);

  fprintf(stderr, "string:%s/n", argv[2]);

  return regtest(argv[1], argv[2]);

  }

  在字符串匹配之前,必须先编译匹配模式,这是通过regcomp实现的。这个函数的原型如下:

  int regcomp (regex_t *compiled, const char *pattern, int cflags)

  参数compiled有一个成员需要关注:re_nsub,代表编译后的子表达式数目,由于需要保存整个匹配到的模式,所以最终匹配的条目数是re_nsub加1。cflags用来修饰匹配模式,可取值如下:

  REG_EXTENDED 启用POSIX正则库扩展,关于该扩展的详细信息可参考POSIX规范

  REG_ICASE 忽略大小写

  REG_NOSUB 不要存储子表达式

  REG_NEWLINE 把换行符作为多行的分隔符,这样'$'可匹配每一行的行尾,'^'匹配每一行的行首,'.'不匹配换行符,[^...]不匹配新行

  编译完模式后从内存中分配子表达式存储空间,然后调用regexec对串进行匹配,该函数原型如下:

  int regexec (regex_t *compiled, char *string, size_t nmatch, regmatch_t matchptr [], int eflags)

  nmatch指明matchptr数组的数目,该数目是compiled->re_nsub+1,也可以让nmatch为0,matchptr为NULL,表示不要保存子表达式。eflags通常为0。

  匹配结束后,匹配到的子表达式在串中的偏移保存在regmatch_t结构中,该结构有两个成员:

  rm_so 子表达式的起始偏移

  rm_eo 子表达式的结束偏移

  这是一个开区间,实际的子表达式在[rm_so,rm_eo)里。

  如果没有匹配的子表达式,比如"f(o*)"匹配"fum",实际匹配到的只有"f",这时rm_so和rm_eo相等,都为1。如果整个模式在没有子表示式的情况下也能匹配,这时rm_so和rm_eo为-1,比如"ba(na)*"匹配"ba"。

  PCRE库

  PCRE库的功能虽然强大,可是并不难使用。详细信息可参考http://www.pcre.org/里的文档,附录有一个例子,比较全面地阐述了如何调用该库。

  PCRE的子表达式和POSIX类似,不过它还引入了一个命名子表达式的概念。比如模式"(?P(?P(/d/d)?/d/d)-(?P/d/d)-(?P/d/d))",其中的date, year, month, day是对子表达式的命名。如何根据这些名称来获取子表达式,PCRE文档有详细的说明。

  附录:pcredemo.c

  /*************************************************

  * PCRE DEMONSTRATION PROGRAM *

  *************************************************/

  /* This is a demonstration program to illustrate the most straightforward ways

  of calling the PCRE regular expression library from a C program. See the

  pcresample documentation for a short discussion.

  Compile thuswise:

  gcc -Wall pcredemo.c -I/usr/local/include -L/usr/local/lib /

  -R/usr/local/lib -lpcre

  

  Replace "/usr/local/include" and "/usr/local/lib" with wherever the include and

  library files for PCRE are installed on your system. Only some operating

  systems (e.g. Solaris) use the -R option.

  */

  #include

  #include

  #include

  #define OVECCOUNT 30 /* should be a multiple of 3 */

  int main(int argc, char **argv)

  {

  pcre *re;

  const char *error;

  char *pattern;

  char *subject;

  unsigned char *name_table;

  int erroffset;

  int find_all;

  int namecount;

  int name_entry_size;

  int ovector[OVECCOUNT];

  int subject_length;

  int rc, i;

  /**************************************************************************

  * First, sort out the command line. There is only one possible option at *

  * the moment, "-g" to request repeated matching to find all occurrences, *

  * like Perl's /g option. We set the variable find_all to a non-zero value *

  * if the -g option is present. Apart from that, there must be exactly two *

  * arguments. *

  **************************************************************************/

  find_all = 0;

  for (i = 1; i
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值