在C/C++语言中使用正则表达式
说起正则表达式(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 titleHello 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 titleHello World/title 222
Pattern: "title(.*)/title"
Total has subexpression: 1
OK, has matched ...
begin: %, len = 4 match: titleHello 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 titleHello 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 titleHello World/title 222
Pattern: "title(.*)/title"
OK, has matched ...
0: titleHello 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 titleHello 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 titleHello 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”写的很好,编译原理的书也有这方面的内容。
c的正确发音
c在英文字母中读作“ [si:]”。“c”是英语字母中的第三个字母,大写为“C”,小写为“c”。字母的含义:1、在数学及计算机科学中,表示十六进制的12。2、在化学中,表示碳的化学符号。3、在乐理中,表示音阶中的C音。4、在国际单位制的电荷中表示库仑。5、在营养学中,表示维生素C。6、在生...
c表示的三种意义
C有三种含义:碳元素、一个碳原子、金刚石(或者石墨)。碳(C)ⅣA族元素。可形成种类繁多的有机化合物,还能形成一系列无机化合物。国际纯粹与应用化学联合会1961年将12C=12确定为相对原子质量的相对标准。天然碳化合物中12C占98.892%(原子分数)、13C占1.108%(原子分数)。14C是在宇宙射线的影响...
c是什么?
c是字母符号。C(大写) 、c(小写)是英文字母顺数第三个,俄语字母顺数第19个。例如:英语单词cloud和“苏联”的俄语缩写СССР的第一个字母就是c。起源:(1)字母C的产生可能是由于一个投掷棒的符号,像在古埃及的象形文字里,并很早出现在闪族的书面当中-大约在公元前1500年的西奈半岛。(...
c的意思是怎么样的?
c的意思:1、在化学中,表示碳的化学符号。2、在乐理中,表示:音阶中的C音,调号中于C音开始的音乐的C大调及C小调,拍子记号中的4\/4拍子。3、在罗马数字中,表示100。4、在国际单位制中,表示电荷量的单位“库仑”。5、在计算机科学中,有C语言、C++、C#、Objective-C等。6、在营养学中,表示...
c在化学中指什么意思
C在化学中有两种含义:1、表示浓度,单位为mol\/L,计算式为:C=n\/V. C=1000ρω\/M。含义:以1升溶液中所含溶质的摩尔数表示的浓度。以单位体积里所含溶质的物质的量(摩尔数)来表示溶液组成的物理量,叫作该溶质的摩尔浓度,又称该溶质物质的量浓度。溶质含量越多,浓度越大。浓度可以用一定...
c是什么意思数学
C是数学中的一种常数,常出现在各种式子中。其代表的是一个固定的数值,通常用来表示某种特定的物理量或者数学常量。C的意义在不同的上下文中有所不同,比如C可能代表光速,圆周率或者其他数学上的常量。在数学上,C代表了需要用作计算基础的一些重要数值,因此不同的C值被广泛应用于各种数学分支中。在...
c在爱情的含义是什么
c在爱情的含义是什么,用各种各样的符号来代替我们想要表达的真实意思是我们对一份感情的含蓄表示,世间万物存在的意义就是我们赋予的内涵,下面分享c在爱情的含义是什么。 c在爱情的含义是什么1 C指的是现在流行的C型爱情观。 C型爱情观 “C型爱情观”指的是对现代爱情关一种新的定义。在爱情中,有进有退、...
c的大写字母是什么?
c的大写字母是C。占四线格的中格,注意要留出一个缺口,不要封住。26个字母英语大小写分别为Aa、Bb、Cc、Dd、Ee、Ff、Gg、Hh、Ii、Jj、Kk、Ll、Mm、Nn、Oo、Pp、Qq、Rr、Ss、Tt、Uu、Vv、Ww、Xx、Yy、Zz。书写英语字母时要按照字母的笔画和字母在三个格中所占据的位置书写,同时每个字母都...
为什么c是组合?
C表示的是组合。C右上角是3,右下角是5,就是说从5个东西选出3个东西的排列组合(与顺序无关)有多少个,计算方法:5!\/3!*(5-3)!=1*2*3*4*5\/1*2*3*1*2=10 跟据任意两边和大于第三边。即为从5个数字里面选出3个数字的组合,有10个,减去不成立的(3,4,7)1个;加上等腰三角...
数学中C是什么意思???
C表示的是组合意思。组合(combination)是一个数学名词。从n个不同的元素中,任取m(m≤n)个元素为一组,叫作从n个不同元素中取出m个元素的一个组合。例如下题:有足够多的3,4,5,6,7米长的木材,取三根组成三角形,请问能组成多少个不同三角形?计算方法:C右上角是3,右下角是5,就是说...
钞谈奥天: 正则表达式(regular expression)是计算机科学中的一个概念,又称规则表达式,通常简写为regex、regexp、RE、regexps、regexes、regexen.正则表达式是一种文本模式.正则表达式是强大、便捷、高效的文本处理工具.正则表达式本身...
灵石县18840101496: 如何在C语言中使用正则表达式 - ?
钞谈奥天: 看到大家讨论这方面的东西,作点贡献聊表各位高手对这个版快的无私奉献 :oops: 如果用户熟悉Linux下的sed、awk、grep或vi,那么对正则表达式这一概念肯定不会陌生.由于它可以极大地简化处理字符串时的复杂 度,因此现在已经在许...
灵石县18840101496: 如何在c/c++中用正则表达式?
钞谈奥天: #include <stdio.h> int main(){ char buffer[200]; FILE* fin = fopen("sample.txt"/*你需要的文件名*/, "r"); fscanf(fin, "%s", buffer);//读取当前第一个字符串 //读完后关闭文件 fclose(fin); } 也可以去www.boost.org看看! 希望可以帮你的忙!也希望你的问题可以早日得到解决!
灵石县18840101496: 在C++里面这个正则表达式要怎么写?用正则表达式^\d*\+\d*j$匹配形如123+456j的复数字符串 - ?
钞谈奥天: ^是界定符,表示匹配字符串的开始;[+-],中括号表示其内的内容都是符合要求的匹配,所以这个表示“+”或者"-";\d,[0-9]的简写形式,也就是匹配数字;$也是界定符,表示匹配字符串的结束;了解以上之后再来看问号(?)和星号(*)...
灵石县18840101496: C语言正则表达式 - ?
钞谈奥天: 现在很多种语言都支持正则表达式,据说有个老外的书不错,精通正则表达式,哎,可惜,我们这小地方买本书比较难,C语言当然支持,许多主流语言都支持,正则表达式可以很大的提升效率,一段小代码就能实现长篇大论的程序,很精彩
灵石县18840101496: C/C++支持正则表达式吗? - ?
钞谈奥天: C++语言特性上不支持.目前标准库中也没有直接的支持.需要另外配置支持正则表达式的库.常用的是boost.regex库,具体资料很多,可以直接搜索.另外还有ATL CAtlRegExp、GRETA等.
灵石县18840101496: 如何用c语言来识别电子邮箱是否正确 - ?
钞谈奥天: 最简单的方式是使用正则表达式.检测邮箱格式的正则表达式:^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$. 1、标准的C和C++都不支持正则表达式,但有一些函数库可以辅助C/C++程序员完成这一功能,其中最著名的当数Philip Hazel的Perl-Compatible ...
灵石县18840101496: 正则表达式可以用在c语言和vb中吗? - ?
钞谈奥天: c语言默认情况下不支持正则表达式 vb可以 Function RegExpTest(patrn, strng) Dim regEx, Match, Matches ' 建立变量. Set regEx = New RegExp ' 建立正则表达式. regEx.Pattern = patrn ' 设置模式. regEx.IgnoreCase = True ' 设置是否区分字符...
灵石县18840101496: C语言的正则表达工具reec怎么用额?
钞谈奥天: 劝你别用了,那个reec我试了下,连个半成品都不算. 本来它连正则表达式的那些\s,*之类的都不支持,还好意思说自己是处理正则的. 另外我试了下,它自己连它的例子运行出来也是错的. 总之要用的话,就是把 main.c reec.c rex.c reio.c四个文件一起编译,然后main.c是例子,需要你自己去改写的.
灵石县18840101496: C++,如果加入regex.h,使用正则式 - ?
钞谈奥天: #include "deelx.h"// 表达式对象 CRegexpT <char> re("\\d*(?=\\.)\\.\\d*", MULTILINE);// 替换 char * newstring = re.Replace("1.12\n1", "");// 其他操作 //.....// 释放字符串 re.ReleaseString(newstring);