在C/C++语言中使用正则表达式

所属分类: 软件教程 / 编程开发 阅读数: 1734
收藏 0 赞 0 分享

  本文所有的内容都来自网络,加上一些个人的理解,不保证正确性,欢迎批评指正
  说起正则表达式(Regular Expression),也许有的朋友天天都在使用,比如grep、vim、sed、awk,只是可能对这个名词不大熟悉。正则表达式一般简写为regex或者regexp,甚至是RE。关于正则表达式的介绍,有很多的文章,用搜索引擎查找就可以找到很不错的使用说明。但是在C/C++语言中如何去使用,相应的介绍比较缺乏。大多数C标准库自带regex,可以通过/usr/include/regex.h去看,或者man regex看使用说明。perl,php等语言更是提供了功能强大的正则表达式,最著名的C语言正则表达式库为PCRE(Perl Compatible Regular Expression)。本文主要对regex和pcre的使用做一点入门介绍。
  1、regex
  regex的使用非常简单,只要看一下示例代码1就能明白(示例代码是从“GNU C 规则表达式入门”这篇文章里摘取出来的,是否为原始出处就
  不得而知了)。
  CODE:#include <stdio.h>
  #include <string.h>
  #include <regex.h>
  #define SUBSLEN 10              /* 匹配子串的数量 */
  #define EBUFLEN 128          /* 错误消息buffer长度 */
  #define BUFLEN 1024          /* 匹配到的字符串buffer长度 */
  int main()
  {
  size_t       len;
  regex_t       re;      /* 存储编译好的正则表达式正则表达式在使用之前要经过编译 */
  regmatch_t    subs [SUBSLEN]; /* 存储匹配到的字符串位置 */
  char          matched [BUFLEN];     /* 存储匹配到的字符串 */
  char          errbuf [EBUFLEN]; /* 存储错误消息 */
  int          err, i;
  char          src    [] = "111 <title>Hello World</title> 222"; /* 源字符串 */
  char          pattern [] = "<title>(.*)</title>"; /* pattern字符串 */
  printf("String : %s\n", src);
  printf("Pattern: \"%s\"\n", pattern);
  /* 编译正则表达式 */
  err = regcomp(&re, pattern, REG_EXTENDED);
  if (err) {
  len = regerror(err, &re, errbuf, sizeof(errbuf));
  printf("error: regcomp: %s\n", errbuf);
  return 1;
  }
  printf("Total has subexpression: %d\n", re.re_nsub);
  /* 执行模式匹配 */
  err = regexec(&re, src, (size_t) SUBSLEN, subs, 0);
  if (err == REG_NOMATCH) { /* 没有匹配成功 */
  printf("Sorry, no match ...\n");
  regfree(&re);
  return 0;
  } else if (err) {   /* 其它错误 */
  len = regerror(err, &re, errbuf, sizeof(errbuf));
  printf("error: regexec: %s\n", errbuf);
  return 1;
  }
  /* 如果不是REG_NOMATCH并且没有其它错误,则模式匹配上 */
  printf("\nOK, has matched ...\n\n");
  for (i = 0; i <= re.re_nsub; i++) {
  len = subs[i].rm_eo - subs[i].rm_so;
  if (i == 0) {
  printf ("begin: %d, len = %d   ", subs[i].rm_so, len); /* 注释1 */
  } else {
  printf("subexpression %d begin: %d, len = %d   ", i, subs[i].rm_so, len);
  }
  memcpy (matched, src + subs[i].rm_so, len);
  matched[len] = '\0';
  printf("match: %s\n", matched);
  }
  regfree(&re); /* 用完了别忘了释放 */
  return (0);
  }
  执行结果是
  CODE:String : 111 <title>Hello World</title> 222
  Pattern: "<title>(.*)</title>"
  Total has subexpression: 1
  OK, has matched ...
  begin: %, len = 4   match: <title>Hello World</title>
  subexpression 1 begin: 11, len = 11   match: Hello World
  从示例程序可以看出,使用之前先用regcomp()编译一下,然后调用regexec()进行实际匹配。如果只是看有没有匹配成功,掌握这2个函数的用法即可。有时候我们想要取得匹配后的子表达式,比如示例中想获得title是什么,需要用小括号 "( )"把子表达式括起来"<title>(.*)</title>",表达式引擎会将小括号 "( )" 包含的表达式所匹配到的字符串记录下来。在获取匹配结果的时候,小括号包含的表达式所匹配到
  的字符串可以单独获取,示例程序就是我用来获取http网页的主题(title)的方式。
  regmatch_t subs[SUBSLEN]是用来存放匹配位置的,subs[0]里存放这个匹配的字符串位置,subs[1]里存放第一个子表达式的匹配位置,也就是例子中的title,通过结构里的rm_so和rm_eo可以取到,这一点很多人不太注意,应该强调一下。
  注释1:开始调试代码的时候是在FreeBSD 6.2上进行的,print出来的len总是0,但print出来的字符串又没错,很是迷惑,把它放到Linux上则完全正常,后来仔细检查才发现rm_so在Linux上是32位,在FreeBSD上是64位,用%d的话实际取的是rm_so的高32位,而不是实际的len,把print rm_so的地方改为%llu就可以了。
  regex虽然简单易用,但对正则表达式的支持不够强大,中文处理也有问题,于是引出了下面要说的PCRE。
  2、PCRE   (http://www.pcre.org
  PCRE的名字就说明了是Perl Compatible,熟悉Perl、PHP的人使用起来完全没有问题。PCRE有非常丰富的使用说明和示例代码(看看
  pcredemo.c就能明白基本的用法),下面的程序只是把上面regex改为pcre。
  CODE:/* Compile thuswise:
  * gcc -Wall pcre1.c -I/usr/local/include -L/usr/local/lib -R/usr/local/lib -lpcre
  *
  */
  #include <stdio.h>
  #include <string.h>
  #include <pcre.h>
  #define OVECCOUNT 30 /* should be a multiple of 3 */
  #define EBUFLEN 128
  #define BUFLEN 1024
  int main()
  {
  pcre          *re;
  const char    *error;
  int          erroffset;
  int          ovector[OVECCOUNT];
  int          rc, i;
  char          src [] = "111 <title>Hello World</title> 222";
  char          pattern [] = "<title>(.*)</title>";
  printf("String : %s\n", src);
  printf("Pattern: \"%s\"\n", pattern);
  re = pcre_compile(pattern, 0, &error, &erroffset, NULL);
  if (re == NULL) {
  printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
  return 1;
  }
  rc = pcre_exec(re, NULL, src, strlen(src), 0, 0, ovector, OVECCOUNT);
  if (rc < 0) {
  if (rc == PCRE_ERROR_NOMATCH) printf("Sorry, no match ...\n");
  else printf("Matching error %d\n", rc);
  free(re);
  return 1;
  }
  printf("\nOK, has matched ...\n\n");
  for (i = 0; i < rc; i++) {
  char *substring_start = src + ovector[2*i];
  int substring_length = ovector[2*i+1] - ovector[2*i];
  printf("%2d: %.*s\n", i, substring_length, substring_start);
  }
  free(re);
  return 0;
  }
  执行结果是:
  CODE:String : 111 <title>Hello World</title> 222
  Pattern: "<title>(.*)</title>"
  OK, has matched ...
  0: <title>Hello World</title>
  1: Hello World
  比较这2个例子可以看出,在regex用的是regcomp()、regexec(),pcre则使用pcre_compile()、pcre_exec(),用法几乎完全一致。
  pcre_compile()有很多选项,详细说明参见http://www.pcre.org/pcre.txt。如果是多行文本,可以设置PCRE_DOTALL的选项pcre_complie(re,
  PCRE_DOTALL,....),表示'.'也匹配回车换行"\r\n"。
  3、pcre++
  pcre++(http://www.daemon.de/PCRE)对pcre做了c++封装,使用起来更加方便。
  CODE:/*
  * g++ pcre2.cpp -I/usr/local/include -L/usr/local/lib -R/usr/local/lib -lpcre++ -lpcre
  */
  #include <string>
  #include <iostream>
  #include <pcre++.h>
  using namespace std;
  using namespace pcrepp;
  int main()
  {
  string src("111 <title>Hello World</title> 222");
  string pattern("<title>(.*)</title>");
  cout << "String : " << src << endl;
  cout << "Pattern : " << pattern << endl;
  Pcre reg(pattern, PCRE_DOTALL);
  if (reg.search(src) == true) { //
  cout << "\nOK, has matched ...\n\n";
  for(int pos = 0; pos < reg.matches(); pos++) {
  cout << pos << ": " << reg[pos] << endl;
  }
  } else {
  cout << "Sorry, no match ...\n";
  return 1;
  }
  return 0;
  }
  执行结果是:
  CODE:String : 111 <title>Hello World</title> 222
  Pattern : <title>(.*)</title>
  OK, has matched ...
  0: Hello World
  4、oniguruma
  还有一个正则表达式的库oniguruma(http://www.geocities.jp/kosako3/oniguruma/),对于东亚文字支持比较好,开始是用在ruby上,也可用于C++,是日本的开发人员编写的。大多数人都不会用到,也就不做介绍了。如果有疑问可以通过email来讨论它的用法。
  5、Regular Expression的内部实现
  关于Regular Expression的实现,用到了不少自动机理论(Automata Theory)的知识,有兴趣的可以找这方面的资料来看,这本书“
  Introduction to Automata Theory, Languages, and Computation”写的很好,编译原理的书也有这方面的内容。

更多精彩内容其他人还在看

PowerDesigner16.6怎么破解?SAP PowerDesigner16.6安装破解详细图文教程

PowerDesigner是一款来自国外的数据库建模工具,最近,很多网友问小编PowerDesigner16.6怎么破解?今天脚本之家小编就给大家带来SAP PowerDesigner16.6安装破解详细图文教程,希望对大家有所帮助
收藏 0 赞 0 分享

WebStorm 2017.3最新汉化激活破解及安装教程(附汉化包+原版下载)

WebStorm 2017中文破解版是一款JavaScript开发工具,是最强大的HTML5编辑器以及最智能的JavaSscript IDE,下面就整理WebStorm 2017.3最新汉化破解教程,并附有汉化包及官方原版程序下载地址
收藏 0 赞 0 分享

PhpStorm 10.0.2怎么激活?PhpStorm 10.0.2激活破解图文教程(附注册码)

PhpStorm 10.0.2怎么激活?对于新手来说最头痛的问题还是激活和使破解的问题,今天脚本之家小编就给大家带来PhpStorm 10.0.2激活破解图文教程(附注册码),希望对大家有所帮助
收藏 0 赞 0 分享

Toad for Oracle 2017完整破解版安装教程(附注册码) 64位

Toad for oracle 2017是一款功能强大的数据库管理软件,支持敏捷数据库开发工作,是一个功能强大、结构紧凑的专业化PL/SQL开发环境,本文提供最新版的Toad for Oracle 2017详细的安装步骤,以及软件下载地址和注册码
收藏 0 赞 0 分享

Aqua Data Studio 18汉化安装破解教程(附DateStopper破解下载)

Aqua Data Studio18中文版是一套完整IDE的数据库开发工具,新版对其通用数据库管理和分析软件的一次重大升级,下面就带来了Aqua Data Studio18最新版详细安装步骤,以及破解方法,仅供参考
收藏 0 赞 0 分享

informatica powercenter 9.x安装与配置图文详细教程(适应于Windows系统)

informatica powercenter是一款使用相当广泛的数据集成平台(ETL工具),本文主要针对目前还不会安装与配置informatica powercenter 9.x程序的朋友们,来图文详细介绍informatica powercenter 9.x安装与配置教程,并
收藏 0 赞 0 分享

Myeclipse 2017 CI8汉化破解教程(附注册激活码)

MyEclipse可用于用户所有的UML, AJAX, Web, Web Services, J2EE, JSP, XML, Struts, JSF, Java Persistence, EJB,扩展数据库支持以及应用程序服务器集成需求,那么Myeclipse 2017 CI8怎
收藏 0 赞 0 分享

CoolFormat 源代码格式化工具使用帮助手册

CoolFormat源代码格式化是一款C\C++\C#\CSS\HTML\Java\JavaScript\JSON\Objective-C\PHP\SQL\XML代码格式化工具。软件可以快速多种风格格式化,并对语言进行着色。界面采用Office 2010风格,并有多种样式可以替换
收藏 0 赞 0 分享

Sublime Text 3怎么设配置浏览默认路径为localhost?

Sublime Text 3怎么设置浏览器打开就是localhost路径?Sublime Text 3编辑程序的时候,需要对代码进行预览,该怎么制定配置浏览器默认的浏览路径为localhost呢?下面我们就来看看详细的教程,需要的朋友可以参考下
收藏 0 赞 0 分享

Visual Studio窗口界面显示黑色很多功能消失了怎么办?

Visual Studio窗口界面显示黑色很多功能消失了怎么办?Visual Studio打开以后,窗口变成黑色的了,新建文件的时候,发现工具栏中少了很多功能,该怎么办呢?下面我们就来看看详细的解决办法,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多