boost regex 正则表达式使用学习

什么是正则表达式?正则表达式是一种用来描述一定数量文本的模式。Regex代表Regular Express。
如果您不知道什么是正则表达式,请看这篇文章http://blog.csdn.net/begtostudy/archive/2007/11/11/1879206.aspx

有了正则表达式的基础,问题是如何使用。我们以boost::regex来说

先看一个网上经典的例子。

#include "stdafx.h"

#include <cstdlib>

#include <stdlib.h>

#include <boost/regex.hpp>

#include <string>

#include <iostream>

using namespace std;

using namespace boost;

regex expression("^select ([a-zA-Z]*) from ([a-zA-Z]*)");

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

{

 std::string in;

 cmatch what;

 cout << "enter test string" << endl;

 getline(cin,in);

 if(regex_match(in.c_str(), what, expression))

 {

for(int i=0;i<what.size();i++)

 cout<<"str :"<<what[i].str()<<endl;

 }

 else

 {

cout<<"Error Input"<<endl;

 }

 return 0;

}
 
==============
结果
输入:select name from table

输出:str:select name from table

 str:name

 str:table

按照我们的要求,字符串被匹配挑出来了。
这在处理大量规则的文本格式的时候很有用,因为它很灵活,一通百通。

首先,即使你拥有了boost库,也需要单独编译regex。
如果你不知道boost库,看这里http://www.stlchina.org/twiki/bin/view.pl/Main/BoostStartIntroduce

网上的介绍:
boost库安装比较麻烦,需要自己编译源文件,我整理了一下,如果仅仅需要做正则表达式,按下面的代码敲就行了:

cmd

vcvars32.bat

cd D:/boost_1_32_0/libs/regex/build

d:

nmake -fvc6.mak

nmake -fvc6.mak install

注意,别看下载下来的数据包没有多大,解压缩之后达到了100多M,编译完之后为109M,占用131M,所以安装时一定注意空出足够的空间,敲入nmake -fvc6.mak后等待的时间比较长,屏幕上还会出现一大堆英语,可以不做考虑。按照步骤往下敲就行了。压缩包内文档很详细,参照文档继续就可以了。

在VC6中集成:Tools->Options->Directories->Include files

加入:D:/boost_1_32_0

我用的是VS2003
做了run.bat

chdir E:/Program/boost_1_34_1

bjam "-sTOOLS=vc-7_1" "-sVC71_ROOT=D:/Program Files/Microsoft Visual Studio .NET 2003/Vc7"  "--prefix=E:/Program/boost" "--builddir=E:/Program/boost_1_34_1/build" "-sBUILD=debug release <runtime-link>static/dynamic" --with-regex install

PAUSE

至于参数,需要参考boost安装介绍http://blog.csdn.net/begtostudy/archive/2007/11/11/1879213.aspx

其他的一些介绍

 bool validate_card_format(const std::string s)
        {
           static const boost::regex e("(//d{4 }[- ]){3}//d{4}");
           return regex_match(s, e);
        }

boost::regex的默认正则表达式语法是perl语法
        boost::regex支持perl regular表达式、POSIX-Extended regular表达式和POSIX-Basic Regular表达式,但默认的表达式语法是perl语法,如果要使用其余两种语法需要在构造表达式的时候明确指定。

        例如,下面两种方法效果相同
        // e1 is a case sensitive Perl regular expression:
        // since Perl is the default option there's no need to explicitly specify the syntax used here:
        boost::regex e1(my_expression);
        // e2 a case insensitive Perl regular expression:
        boost::regex e2(my_expression, boost::regex::perl|boost::regex::icase);

perl正则表达式语法
        perl正则表达式语法可参见《perl语言入门》第7、8、9章或boost的文档。这里列出的语法是不全面的,而且部分说明可能并不清楚。

        . 任意字符;使用match_no_dot_null标志时不匹配NULL字符; 使用match_not_dot_newline时不匹配换行字符

        ^ 匹配行的开始
        $ 匹配行的结束
        * 重复零次或则更多,例如a*b可匹配b,ab,aab,aaaaaaab
        + 重复一次以上,例如a+b可匹配ab,aab,aaaaaaaab。但不能匹配b了
        ? 零次或则一次,例如ca?b匹配cb,cab但不匹被caab   
        a{n} 匹配字符'a'重复n次
        a{n,},字符a重复n次以上(含n次)
        a{n,m} a重复n到m次(含)

        *?   匹配前一个原子零次以上
        +?   匹配前一个原子一次以上
        ??   匹配前一个原子零次以上
        {n,}?  匹配前一个原子n次以上(含)
        {n,m?  匹配前一个原子n到m次(含)

        | 或操作,例如ab(d|ef)匹配abd或则abef
        [] 字符集操作,例如[abc]将匹配任何单个字符'a','b','c'
        [a-d],表示a、b、c、d
        ^否操作,例如[^a-c]表示a至c之外的所有字符


boost::regex对unicode编码的支持
        boost::regex使用ICU来实现对unicode及unicode变种的支持,这需要在编译boost的时候指出是否使用ICU以及ICU所在的目录。否则编译出来的boost::regex不支持unicode编码。其中boost::wregex支持unicode编码的搜索,如果要搜索UTF-8、UTF-16、UFT-32编码的字符串,则要用boost::u32regex。注意boost::wregex只能支持unicode编码,不能支持uft编码。

搜索时如何忽略大小写
        如果要在搜索时忽略大小写(即大小写不敏感),则要用到表达式选项boost::regex::icase,例如: boost::regex e2(my_expression, boost::regex::perl|boost::regex::icase);

 

模板类:

l         basic_regex          用来保存一个“正则表达式”的类。

l         sub_match             继承于 pair<Iterator,Iterator> 迭代器组,用来表示匹配的一个结果。

l         match_results             sub_match 的容器,用来表示一次搜索或匹配算法的所有结果,类似于 vector<sub_match>

算法:

l         regex_math   匹配算法,测试一个字符串是否和一个正则式匹配,并通过 match_results 返回结果。

l         regex_find      查找算法,查找字符串的一个和正则式匹配的字串,并通过 match_results 返回结果。

l         regex_format        替换算法,查找字符串中的所有匹配正则式的字串,并使用“格式化字符”串替换。

迭代器:

l         regex_iterator       枚举一个字符串中所有匹配的字串, regex_iterator 的结果相当于 match_results

l         regex_token_iterator 枚举一个字符串中所有匹配的字串, regex_iterator 的结果相当于 sub_match

 

详述

l       basic_regex

template <class charT, class traits = regex_traits<charT>, class Allocator = std::allocator<charT>  >

class basic_regex;

typedef basic_regex<char> regex;

typedef basic_regex<wchar_t> wregex;

很明显, charT 是正则式的字符类型, regex wregex basic_regex 的两个特化。

注意,正则式的字符类型要和需要匹配的字符串的字符类型相同。例如:不能在 regex_find 算法中分别使用 string wregex 最为参数,要么是 string regex ,要么是 wstring wregex

构造函数:

basic_regex re

产生空的正则式

basic_regex re(str)

正则式为 str str 可以为 basic_string ,也可以是 0 结尾的 char* 字符串。

Basic_regex re(re2)

拷贝构造。

basic_regex re(str,flag)

正则式为 str ,使用 flag 语法选项, flag 是一组常量的组合。例如: icase 可以使正则式匹配忽略大小写。

basic_regex re(beg,end)

使用迭代器构造正则式。可以是 basic_string 的迭代器,也可以是 const char*

basic_regex re(beg,end,flag)

使用迭代器构造正则式, flag 是语法选项。

常用的语法选项:

regex_constants::normal

默认的语法。符合 EMCAScript,JavaScript 中的正则式。

regex_constants::icase

匹配的时候忽略大小写。

regex_constants::nosubs

不把匹配的子串保存进 match_results 结构。

regex_constants::collate

对于 [a-b] 的匹配,考虑地区

 

语法选项通过或运算来结合。在 basic_regex 中这些语法选项也进行了定义,所以可以写成 regex::normal ,这要比 regex_constants 少打好几个字母了吧! J

assign 成员函数:

re.assign(re2)

复制一个正则式

re.assign(str)

正则式为 str

re.assign(str, flag)

正则式为 str ,使用 flag 语法选项, flag 是一组常量的组合。

re.assign(beg, end)

使用迭代器构造正则式。

re.assign(beg, end, flag)

使用迭代器构造正则式, flag 是语法选项。

 

其实 basic_regex 很多用法和 basic_string 很像,因为正则表达式也是个字符串嘛!

迭代器:

regex::iterator it

常迭代器类型,即 const_iterator

re.begin()

返回的是常迭代器哦! const_iterator

re.end()

没有逆向迭代器。

例如: copy(re.begin(), re.end(), ostream_iterator<char>(cout));

其他:

re.size()

正则表达式长度,即 str 的长度。

re.max_size()

正则表达式的最大长度。

re.empty()

长度是否为 0

re.mark_count()

返回正则式的组数,一般情况下为小括号对数 +1 。在 boost.regex 中使用小括号分组,详情请看下面的算法详解。

re.flags()

返回语法选项。

cout<<re

正则式的流输出,相当于上面示例的 copy 算法。

swap

成员函数,全局函数都有

re.imbue(loc)

设置 local loc ,返回原来的 local

re.getloc()

得到当前 local

==,!=,<,<=,>,>=

比较运算符重载

 

l       sub_match

sub_match 是一个迭代器组,表示正则式中的一个匹配。

template <class BidirectionalIterator>

class sub_match : public std::pair<BidirectionalIterator, BidirectionalIterator>;

boost 没有提供 sub_match 的任何特化,因为我们不会显示的声明一个 sub_match 变量。 sub_match 是作为 match_results 的元素用的。比如: match_results operator[] 和迭代器返回的就是一个特化的 sub_match

唯一的成员变量:

bool matched  是否匹配。

成员函数:

length()

返回长度,即两个迭代器之间的距离。

operator basic_string< value_type>()

隐式的 basic_string 转换。

str()

显式的 basic_string 转换。

还有就是一大堆的比较操作符的重载了,这里就不多说了。

 

l       match_results

match_results 相当于 sub_match 的容器,用于表示正则式算法的返回结果。

template <class BidirectionalIterator,

          class Allocator = allocator<sub_match<BidirectionalIterator> >

class match_results;

 

typedef match_results<const char*> cmatch;

typedef match_results<const wchar_t*> wcmatch;

typedef match_results<string::const_iterator> smatch;

typedef match_results<wstring::const_iterator> wsmatch;

声明很简单,有四个特化可以直接使用,不过要注意 string char* 字符串使用的 match_results 是不同的。

成员函数:

m.size()

容量。

m.max_size()

最大容量。

m.empty()

容量是否为 0

m[n]

n 个元素,即 sub_match

m.prefix()

返回代表前缀的 sub_match ,前缀指字符串的开头到第一个匹配的开头。

m.suffix()

返回代表后缀的 sub_match ,后缀之最后一个匹配的结尾到字符串的结尾。

m.length(n)

返回第 n 个元素的长度,即 m[n].size()

m.position(n)

返回第 n 个元素的位置。

cout<<m

流输出,输出整个匹配,相当于 cout<<m[0] 。因为第 0 个元素是整个匹配,详细情况请看下面的解释。

m.format(fmtstr)

使用格式化字符串,格式化结果,返回字符串

m.format(fmtstr,flags)

使用格式化字符串,格式化结果,返回字符串, flags 是格式化选项。

m.format(out,fmtstr)

同上,但是使用输出迭代器输出结果。

m.format(out.fmtstr,flags)

同上,但是使用输出迭代器输出结果。

迭代器:

smatch::iterator

迭代器,常迭代器

smatch::const_iterator

同上

m.begin()

返回常迭代器

m.end()

同上

 

最后,说一个实例

我处理一个文本

            实际值/-20.031,-1.896,-2.861,-1,0,0

提取其中的数字

regex exp("/s*实际值/(-?[0-9.]+),(-?[0-9.]+),(-?[0-9.]+),(-?[0-9.]+),(-?[0-9.]+),(-?[0-9.]+)$");

大家看看还有没有更好的写法?

 

 

 

上一篇 learning boost 中,我们已经说完了 regex 中的三个模板类,这一篇我们要来使用这些类。我们通过三个算法来使用正则式, regex_match regex_search regex_replace

regex_match

regex_match 算法用来测试一个字符串是否完全匹配正则式。让我们来看一下 regex_match 的使用:

if (regex_match(str, m, re))

{

    ...

}

str 是一个字符串,可以是 string wstring char * 或者 wchar_t *

m match_results ,它通过引用传入参数,来保存匹配的结果, m 要和 str 的类型匹配,可以是 smatch wsmatch cmatch wcmatch ,用来分别对应 string wstring char * 或者 wchar_t* str

re 就是正则表达式了,一般来说是 regex wregex

str m re 的类型如下:

str 类型

m 类型

re 类型

string

smatch (match_results<string::const_iterator>)

regex (basic_regex<char>)

wstring

wsmatch (match_results<wstring::const_iterator>)

wregex (basic_regex<wchar_t>)

char*

cmatch (match_results<const char*>)

regex (basic_regex<char>)

wchar_t*

wcmatch (match_results<const wchar_t*>)

wregex (basic_regex<wchar_t>)

 

函数的返回值表示字符串是否完全匹配正则表达式,当返回 true 的时候, m 保存了匹配的结果;返回 false m 未定义。

下面让我们来看一下,当函数返回 true 的时候, m 是怎么样的。

m.size() == re.mark_count()

还记得 re.mark_count() 返回的是什么吗?在上一篇中说的是 re.mark_count() 返回的时正则式的“组数”,并没有详细解释。这里我要详细解释一下。

其实,这个“组数”在 boost regex 中叫做 sub-expression sub-expression 就是在正则式中使用小括号括起来的一部分,正则式本身是一个 sub-expression ,所以 re.mark_count() 等于小括号对数 +1

m.prefix() m.suffix()

这两个返回的是 sub_match 类型(相当于一个迭代器组)。在 regex_match 算法中,这两个返回的 sub_match 都是空的,他们的值如下:( sub_match 继承于 pair ,所以有 first second 成员哦)

m.prefix().first == str.begin()

m.prefix().second == str.begin()

m.prefix().matched == false

m.suffix().first == str.end()

m.suffix().second == str.end()

m.suffix().matched == false

因为 regex_match 是完全匹配,即整个字符串和正则式匹配,所以前缀和后缀都是空的。

m[0]

返回第 0 个匹配的,由于 regex_match 是完全匹配,所以

m[0].first == str.begin()

m[0].second == str.end()

m[0].matched == true

m[n] , n<m.size()

返回第 n 个匹配的 sub-expression

m[n].matched 表示第 n sub-expression 是否在字符串中存在。整个 regex 匹配,但是 sub_exp 可能匹配的是空的,例如 ”(a*)” 就有可以匹配空。

m[n].first m[n].second 表示匹配的范围。如果匹配空的话,都为 str.end()

 

根据我的测试, m[1],m[2],...,m[n] 的顺序是按照正则式的左小括号的顺序来的 ,例如对于正则式 ”((a)bc)d(efg)” ,如果匹配了一个字符串的话(字符串只可能是 ”abcdefg” ),则

m[0] == “abcdefg”  sub_match 重载了 == 运算符使得可以和一个字符串比较)

m[1] == “abc”

m[2] == “a”

m[3] == “efg”

 

regex_match 的其它用法

regex_match(str,re)

只测试是否匹配,不需要匹配的结果

regex_match(beg,end,re)

输入的是迭代器

regex_match(beg,end,m,re)

注意 m 的类型为 match_results<iterator>

regex_match(str,m,re,flag)

flag 是匹配选项,默认是的 regex_constants::match_default

 

regex_search

regex_search 的用法基本上和 regex_match 一样。

if (regex_search(str, m, re))

{

    ...

}

regex_search 不要求 str 完全匹配 re ,只要 str 中的一个字串匹配 re 就可以了。所以, m.prefix() m.suffix() 不一定为空。

regex_search 是从左往右匹配,而且尽量匹配长的字串。

 

 

三:简单的例子
    std::string regstr = "a+";
    boost::regex expression(regstr);
    std::string testString = "aaa";

    // 匹配至少一个a
    if( boost::regex_match(testString, expression) )
    {
        std::cout<< "Match" << std::endl;
    }
    else
    {
        std::cout<< "Not Match" << std::endl;
    }

四:regex_match例子代码学习
1 我们经常会看一个字符串是不是合法的IP地址,合法的IP地址需要符合以下这个特征:
  xxx.xxx.xxx.xxx 其中xxx是不超过255的整数
正则表达式找到上面的这种形式的字符串相当容易,只是判断xxx是否超过255就比较困难了(因为正则表达式是处理的文本,而非数字)
OK,我们先来处理一个数字,即:xxx。找到一种表达式来处理这个数字,并且保证这个数字不会超过255
第一种情况:x,即只有一个数字,它可以是0~9 ,用/d 表示
第二种情况:xx,即有两个数字,它可以是00~99,用/d/d 表示
第三种情况:xxx,这种情况分为两种,一种是 1xx,可以用 1/d/d 表示
                                   另外一种是 2xx,这又分为两种 2[1234]/d
                                                             和 25[12345]
好了组合起来
1?/d{1,2}|2[1234]/d|25[12345]
既可以标识一个不大于255的数字字符串

嗯,我们现在需要重复这种情况既可:
(1?/d{1,2}|2[1234]/d|25[12345])/.(1?/d{1,2}|2[1234]/d|25[12345])/.(1?/d{1,2}|2[1234]/d|25[12345])/.(1?/d{1,2}|2[1234]/d|25[12345])

呵呵,长是长了点,我试图用boost支持的子表达式缩短,但是没有达到效果,请各位了解boost的正则表达式的达人指点:
(1?/d{1,2}|2[1234]/d|25[12345])/./1$/./1$/./1$
(参看反向索引: http://www.boost.org/libs/regex/doc/syntax_perl.html
似乎反向只能匹配与第一个字符完全一样的字符串,与我们的需求不同)

Example:
std:: string  regstr  =   " ( 1?//d{1,2}|2[1234]//d|25[12345])//. ( 1?//d{1,2}|2[1234]//d|25[12345])//. ( 1?//d{1,2}|2[1234]//d|25[12345])//. ( 1?//d{1,2}|2[1234]//d|25[12345]) " ;
boost::regex expression(regstr);
std::
string  testString  =   " 192.168.4.1 " ;
if ( boost::regex_match(testString, expression) )
{
    std::cout
<<   " This is ip address "   <<  std::endl;
}
else
{
    std::cout
<<   " This is not ip address "   <<  std::endl;
}

2 我们来看看 regex_match的另外一个函数原型
template <class ST, class SA, class Allocator, class charT, class traits>
    bool regex_match (const basic_string<charT, ST, SA>& s,
    match_results <typename basic_string<charT, ST, SA>::const_iterator, Allocator>& m,
    const basic_regex <charT, traits>& e, match_flag_type flags = match_default);

template <class BidirectionalIterator, class Allocator, class charT, class traits>
bool regex_match(BidirectionalIterator first, BidirectionalIterator last,
match_results <BidirectionalIterator, Allocator>& m,
const basic_regex <charT, traits>& e,
match_flag_type flags = match_default);
 
注意参数m,如果这个函数返回false的话,m无定义。如果返回true的话,m的定义如下

Element

Value

m.size()

e.mark_count()

m.empty()

false

m.prefix().first

first

m.prefix().last

first

m.prefix().matched

false

m.suffix().first

last

m.suffix().last

last

m.suffix().matched

false

m[0].first

first

m[0].second

last

m[0].matched

true if a full match was found, and false if it was a partial match (found as a result of the match_partial flag being set).

m[n].first

For all integers n < m.size(), the start of the sequence that matched sub-expression n . Alternatively, if sub-expression n did not participate in the match, then last .

m[n].second

For all integers n < m.size(), the end of the sequence that matched sub-expression n . Alternatively, if sub-expression n did not participate in the match, then last .

m[n].matched

For all integers n < m.size(), true if sub-expression n participated in the match, false otherwise.

Example:
std:: string  regstr  =   " (1?//d{1,2}|2[1234]//d|25[12345])//.(1?//d{1,2}|2[1234]//d|25[12345])//.(1?//d{1,2}|2[1234]//d|25[12345])//.(1?//d{1,2}|2[1234]//d|25[12345]) " ;
boost::regex expression(regstr);
std::
string  testString  =   " 192.168.4.1 " ;
boost::smatch what;
if ( boost::regex_match(testString, what, expression) )
{
    std::cout
<<   " This is ip address "   <<  std::endl;
    
for ( int  i  =   1 ;i  <=   4 ;i ++ )
    {
        std::
string  msg(what[i].first, what[i].second);
        std::cout
<<  i  <<   " "   <<  msg.c_str()  <<  std::endl;
    }
}
else
{
    std::cout
<<   " This is not ip address "   <<  std::endl;
}
这个例子会把所有的IP的单个数字答应出来:
This is ip address
1:192
2:168
3:4
4:1

 五: regex_search 学习
regex_search与regex_match基本相同,只不过regex_search不要求全部匹配,即部份匹配(查找)即可。
简单例子:

std:: string  regstr  =   " (//d+) " ;
boost::regex expression(regstr);
std::
string  testString  =   " 192.168.4.1 " ;
boost::smatch what;
if ( boost::regex_search(testString, expression) )
{
    std::cout
<<   " Have digit "   <<  std::endl; 
}

上面这个例子检测给出的字符串中是否包含数字。

好了,再来一个例子,用于打印出所有的数字

std:: string  regstr  =   " (//d+) " ;
boost::regex expression(regstr);
std::
string  testString  =   " 192.168.4.1 " ;
boost::smatch what;
std::
string ::const_iterator start  =  testString.begin();
std::
string ::const_iterator end  =  testString.end();
while ( boost::regex_search(start, end, what, expression) )
{
    std::cout
<<   " Have digit: "  ; 
    std::
string  msg(what[ 1 ].first, what[ 1 ].second);
    std::cout
<<  msg.c_str()  <<  std::endl;
    start 
=  what[ 0 ].second;
}

打印出:
Have digit:192
Have digit:168
Have digit:4
Have digit:1

六:关于重复的贪婪
我们先来一个例子:
std:: string  regstr  =   " (.*)(age)(.*)(//d{2}) " ;
boost::regex expression(regstr);
std::
string  testString  =   " My age is 28 His age is 27 " ;
boost::smatch what;
std::
string ::const_iterator start  =  testString.begin();
std::
string ::const_iterator end  =  testString.end();
while ( boost::regex_search(start, end, what, expression) )
{

    std::
string  name(what[ 1 ].first, what[ 1 ].second);
    std::
string  age(what[ 4 ].first, what[ 4 ].second);
    std::cout
<<   " Name: "   <<  name.c_str()  <<  std::endl;
    std::cout
<<   " Age: "   << age.c_str()  <<  std::endl;
    start 
=  what[ 0 ].second;
}

我们希望得到的是打印人名,然后打印年龄。但是效果令我们大失所望:
Name:My age is 28 His
Age:27

嗯,查找原因:这是由于"+"号或者"*"号等重复符号带来的副作用,这些符号会消耗尽可能多的输入,使之是“贪婪”的。即正则表达式(.*)会匹配最长的串,而不是匹配最短的成功串。
如何使得这些重复的符号不再“贪婪”,我们在重复符号后加上"?"即可。
std:: string  regstr  =   " (.*?)(age)(.*?)(//d{2}) " ;
boost::regex expression(regstr);
std::
string  testString  =   " My age is 28 His age is 27 " ;
boost::smatch what;
std::
string ::const_iterator start  =  testString.begin();
std::
string ::const_iterator end  =  testString.end();
while ( boost::regex_search(start, end, what, expression) )
{

    std::
string  name(what[ 1 ].first, what[ 1 ].second);
    std::
string  age(what[ 4 ].first, what[ 4 ].second);
    std::cout
<<   " Name: "   <<  name.c_str()  <<  std::endl;
    std::cout
<<   " Age: "   << age.c_str()  <<  std::endl;
    start 
=  what[ 0 ].second;
}
打印输出:
Name:My
Age:28
Name: His
Age:27

七: regex_replace 学习
写了个去除左侧无效字符(空格,回车,TAB)的正则表达式。
std:: string  testString  =   "     /r/n Hello        World  !  GoodBye  World/r/n " ;
std::
string  TrimLeft  =   " ([//s//r//n//t]*)(//w*.*) " ;
boost::regex expression(TrimLeft);
testString 
=  boost::regex_replace( testString, expression,  " $2 "  );
std::cout
<<   " TrimLeft: "   <<  testString  << std::endl;
打印输出:
TrimLeft:Hello          World  !  GoodBye  World
 
/
 
关于匹配结果集的一些定义:
typedef match_results<const char*> cmatch;
typedef match_results<std::string::const_iterator> smatch;
typedef match_results<const wchar_t*> wcmatch;
typedef match_results<std::wstring::const_iterator> wsmatch;
在match_results中有如下定义:
class match_results
{
 #ifndef BOOST_NO_STD_ALLOCATOR
    typedef          std::vector<sub_match<BidiIterator>, Allocator> vector_type;
 #else
    typedef          std::vector<sub_match<BidiIterator> >           vector_type;
 #endif
 .....
 private:
    vector_type            m_subs; // subexpressions
    BidiIterator   m_base; // where the search started from
    sub_match<BidiIterator> m_null; // a null match
}
BidiIterator作为特化类型,const char* 特化为cmatch,std::string::const_iterator 特化为smatch。
从上面可以看出,match_results其实是对两种特化的vector<sub_match<>>集合的封装。但它同样提供了如下定义
   typedef typename vector_type::const_iterator                             const_iterator;
   typedef          const_iterator                                          iterator;
供我们来间接操作vector<sub_match<>>。
为了可以像vector一样,透明的使用match_results,它重载了begin(),end(),at(),[]等方法和运算符。
同时,也增加了如 prefix(),suffix()。
接下来,我们来看sub_match的定义:
template <class BidiIterator>
struct sub_match : public std::pair<BidiIterator, BidiIterator>
{
   typedef          BidiIterator                                                     iterator;
   typedef          BidiIterator                                                     const_iterator;
   bool matched;
}
BidiIterator接受const char *或std::string::const_iterator特化。
sub_match仅有一个数据成员,pair<>的first和end分别指向匹配串的开始和结尾。
如const char *时,first分别指向串的起始指针,而std::string::const_iterator时,指向string::begin()和string::end()迭代器。
sub_match提供一个方法str(),它总是返回string类型。
应用举例:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <boost/regex.hpp>
using namespace std;
using namespace boost;
int _tmain(int argc, _TCHAR* argv[])
{
 regex re("hello");
 printf("re.mark_count = %d /n", re.mark_count());   //打印子表达式的个数,这里输出1
 string sss = "hello hello";
 cmatch what;
 while (regex_search(sss.c_str(), what, re))
 {
  //进行多种方式进行打印
  //(*iter)和what[0]为sub_match值,调用其str()方法返回string类型
  cmatch::iterator iter = what.begin();
  cout << (*iter).str().c_str() << endl;
  cout << what[0].str().c_str() << endl;
  cout << what[0] << endl; // 对 << 进行了重载,间接调用了str();
  
  //suffix()指向每个匹配串的尾部
  cout << what.suffix() << endl;
  sss = what.suffix();
 }
 return 0;
}
另外,还有一个很重要的名词“子语句”,正则表达式以“()“表示子语句,因为表达式本身也是一个语句,所以子语句个数为()数+1,
它们分别按"("的位置进行排序,表达式本身为0号索引。
应用举例:
int main()
{
 string sss = "hello hello";
 regex re2(".*(he).*(he).*");
 smatch result2;
 if (regex_match(sss, result2, re2))
 {
  for (int i = 0; i < result2.size(); i ++)
   cout << result2[i] << endl;
 }
 else
 {
  cout << "no match" << endl;
 }
 
 return 0;
}
输出结果:
hello hello
he
he
我们再举个*贪婪的例子
int main()
{
 string sss = "he1llo he2llo";
 regex re2 = string(".*(he//d).*");
 smatch result2;
 if (regex_match(sss, result2, re2))
 {
  for (int i = 0; i < result2.size(); i ++)
   cout << result2[i] << endl;
 }
 else
 {
  cout << "no match" << endl;
 }
 return 0;
}
输出结果:
he2
修改为:
 regex re2 = string(".*?(he//d).*");
输出结果:
he1
替换用法:
内部机制是search所有的,并一一替换
 regex re3("([//s//t//r//n]*)( //w *.*)");
 string str3 = "   hello   ";
 str3 = regex_replace(str3, re3, "$2");
 regex re4("l");
 str3 = regex_replace(str3, re4, "");
 cout << str3 << endl;

关于正则表达式的Flag定义:
namespace regex_constants{
 enum flag_type_
 {
  icase = ::boost::regbase::icase,
 }
 typedef ::boost::regbase::flag_type syntax_option_type;
}
typedef regex_constants::syntax_option_type   flag_type;
正则表达式忽略小写的写法有:
boost::regbase::icase
regex_constants::icase
boost::regex::icase   这个定义没有找到
举例(实现一个已有表达式转化为忽略大小写的)
 string ttt = re3.str();
 printf("%s", ttt.c_str());
 regex re5(ttt, regex::icase);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值