1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > c++中正则表达式(regex)

c++中正则表达式(regex)

时间:2018-12-15 14:36:36

相关推荐

c++中正则表达式(regex)

/article/cpp11-regex-code.html

regex库概览

1.basic_regex:正则表达式是一个通用的模板

typedef basic_regex<char> regex;

typedef basic_regex<char_t> wregex;

2.regex_match:将一个字符序列和正则表达式匹配

3.regex_search:寻找字符序列中的子串与正则表达式匹配的

结果,在找到地一个匹配的结果后就停止匹配查找

4.regex_replace:使用格式化的替换文本,替换正则表达式匹配到

字符序列的地方

5.reegx_iterator:迭代器,用来匹配所有的子串

6.match_results:容器类,保存正则表达式的结果

7.sub_match:容器类,保存子正则表达式匹配的字符序列

ECMASCRIPT正则表达式语法

正则表达式式的语法基本大同小异,在这里就浪费篇幅细抠了。ECMASCRIPT正则表达式的语法知识可以参考W3CSCHOOL。

构造正则表达式

构造正则表达式用到一个类:basic_regex。basic_regex是一个正则表达式的通用类模板,对char和wchar_t类型都有对应的特化:

typedefbasic_regex<char>regex;typedefbasic_regex<wchar_t>wregex

//默认构造函数,将匹配任何的字符序列basic_regex();//用一个以‘\0’结束的字符串s构造一个正则表达式explicitbasic_regex(constCharT*s,flag_typef=std::regex_constants::ECMAScript);//同上,但是制定了用于构造的字符串s的长度为countbasic_regex(constCharT*s,std::size_tcount,flag_typef=std::regex_constants::ECMAScript);//拷贝构造,不赘述basic_regex(constbasic_regex&other);//移动构造函数basic_regex(basic_regex&&other);//以basic_string类型的str构造正则表达式template<classST,classSA>explicitbasic_regex(conststd::basic_string<CharT,ST,SA>&str,flag_typef=std::regex_constants::ECMAScript);//指定范围[first,last)内的字符串构造正则表达式template<classForwardIt>basic_regex(ForwardItfirst,ForwardItlast,flag_typef=std::regex_constants::ECMAScript);//使用initializer_list构造basic_regex(std::initializer_list<CharT>init,flag_typef=std::regex_constants::ECMAScript);

以上除默认构造之外的构造函数,都有一个flag_type类型的参数用于指定正则表达式的语法,ECMASCRIPT、basic、extended、awk、grep和egrep均是可选的值。除此之外还有其他几种可能的的标志,用于改变正则表达式匹配时的规则和行为:

flag_type

有了构造函数之后,现在我们就可以先构造出一个提取http链接的正则表达式:

std::stringpattern("http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?");//匹配规则很简单,如果有疑惑,可以对照语法查看std::regexr(pattern);

值得一提的是在C++中’\'这个字符需要转义,因此所有ECMASCRIPT正则表达式语法中的’\'都需要写成“\\”的形式。我测试的时候,这段regex如果没有加转义,在gcc中会给出警告提示.

regex_search()只查找到第一个匹配的子序列

根据函数的字面语义,我们可能会错误的选择regex_search()这个函数来进行匹配。其函数原型也有6个重载的版本,用法也是大同小异,函数返回值是bool值,成功返回true,失败返回false。鉴于篇幅,我们只看我们下面要使用的这个:

template<classSTraits,classSAlloc,classAlloc,classCharT,classTraits>boolregex_search(conststd::basic_string<CharT,STraits,SAlloc>&s,std::match_results<typenamestd::basic_string<CharT,STraits,SAlloc>::const_iterator,Alloc>&m,conststd::basic_regex<CharT,Traits>&e,std::regex_constants::match_flag_typeflags=std::regex_constants::match_default);

第一个参数s是std::basic_string类型的,它是我们待匹配的字符序列,参数m是一个match_results的容器用于存放匹配到的结果,参数e则是用来存放我们之前构造的正则表达式对象。flags参数值得一提,它的类型是std::regex_constants::match_flag_type,语义上匹配标志的意思。正如在构造正则表达式对象时我们可以指定选项如何处理正则表达式一样,在匹配的过程中我们依然可以指定另外的标志来控制匹配的规则。这些标志的具体含义,我从引用过来,用的时候查一下就可以了:

根据参数类型,于是我们构造了这样的调用:

std::smatchresults;<br>regex_search(html,results,r);

不过,标准库规定regex_search()在查找到第一个匹配的子串后,就会停止查找!在本程序中,results参数只带回了第一个满足条件的http链接。这显然并不能满足我们要提取网页中所有HTTP链接需要。

使用regex_iterator匹配所有子串

严格意义上regex_iterator是一种迭代器适配器,它用来绑定要匹配的字符序列和regex对象。regex_iterator的默认构造函数比较特殊,就直接构造了一个尾后迭代器。另外一个构造函数原型:

regex_iterator(BidirIta,BidirItb,//分别是待匹配字符序列的首迭代器和尾后迭代器constregex_type&re,//regex对象std::regex_constants::match_flag_typem=std::regex_constants::match_default);//标志,同上面的regex_search()中的

和上边的regex_search()一样,regex_iterator的构造函数中也有std::regex_constants::match_flag_type类型的参数,用法一样。其实regex_iterator的内部实现就是调用了regex_search(),这个参数是用来传递给regex_search()的。用gif或许可以演示的比较形象一点,具体是这样工作的(颜色加深部分,表示可以匹配的子序列):

首先在构造regex_iterator的时候,构造函数中首先就调用一次regex_search()将迭代器it指向了第一个匹配的子序列。以后的每一次迭代的过程中(++it),都会在以后剩下的子序列中继续调用regex_search(),直到迭代器走到最后。it就一直“指向”了匹配的子序列。

知道了原理,我们写起来代码就轻松多了。结合前面的部分我们,这个程序就基本写好了:

#include<iostream>#include<regex>#include<string>intmain(){std::stringtmp,html;while(getline(std::cin,tmp)){tmp+='\n';html+=tmp;}std::stringpattern("http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?”);pattern=“[[:alpha:]]*”+pattern+“[[:alpha:]]*”;std::regexr(pattern);for(std::sregex_iteratorit(html.begin(),html.end(),r),end;//end是尾后迭代器,regex_iterator是regex_iterator的string类型的版本it!=end;++it){std::cout<<it->str()<<std::endl;}}下载本页的html源码保存为test.html,编译这个源码测试一下,大功告成:[regex]g++regex.cpp-std=c++11-omain[regex]main<test.html

regex和异常处理

如果我们的正则表达式存在错误,则在运行的时候标准库会抛出一个regex_error异常,他有一个名为code的成员,用于标记错误的类型,具体错误值和语义如下表所示:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。