Boost xpressive 正则表达式

正则表达式能方便处理文本问题,比如验证,匹配,查找,替换等。而boost xpressive提供动态和静态方式,静态方式类似于boost.spirit语法分析器,使用操作符重载生成编译器的表达式对象,可以在编译器进行正则表达式的语法检查。动态方式以字符串作为表达式对象,在运行时进行语法检查和处理。通常我们不必关心那种方式,因为在boost中它们已经融合,所以两者可以混用。

正则表达式语法

  1. 点号. 单字符通配符
  2. ^ 匹配行的开头
  3. $ 匹配行的末尾
  4. () 用于定义一个正则表达式的匹配子元素,可以被引用或者重复
  5. * 表示前面的元素可以重复任意多次(n >= 0)
  6. + 表示前面的元素可以重复一次或多次 (n > 0)
  7. ? 表示前面的元素重复0次或1次(n=0, 1)
  8. {}可以手动设定重复次数,{n}重复x=n次,{n, }重复>=n次,{n, m}即n<=x<=m
  9. []用于定义字符集合,可以列出单个字符,或者范围,或者集合的补集
  10. \转义字符,特殊字符经转义后与自身匹配
  11. |表示逻辑或的概念,匹配它两侧的元素之一
  12. \d 匹配数字,相当于[0-9]
  13. \w 匹配字母,相当于[a-z]
  14. \s 匹配空格
Example:
1. "a." 可能表示ab, a0
2. "(a*)(b|c+)" 两个子表达式,任意数量的a,然后接一个b或者一个以上的c,如:aaab,aaccc
3.  "[abc]?.\{\}" abc三个字符之一可以出现0次或一次,然后是任意字符,接一个{},如:a={},c2{}

xpressive中重要的三个类:basic_regex,match_results,sub_match

basic_regex 浅析

template <typename BidiIter>
struct basic_regex
{
    basic_regex();
    basic_regex(basic_regex const &);
    regex_id_type regex_id() const;//唯一ID
    std::size_t mark_count() const;//子表达式个数
    void swap(basic_regex &);
    static basic_regex compile(InputRange const & pat); //静态工厂函数
};

typedef basic_regex<std::string::const_iterator> sregex;
typedef basic_regex<char const *> cregex;

注意最后的sregex和cregex,分别用户操作std::string,和操作字符数组。而basic_regex的核心功能是静态成员函数compile(),它是一个工厂方法,可以根据正则表达式参数创建一个basic_regex对象。

template <typename BidiIter>
struct match_results
{
    size_type size() const;//子表达式个数
    bool empty() const;
    template <typename Sub>
    const_reference operator[](Sub const & i) const; //获取子表达式
};

typedef match_results<std::string::const_iterator> smatch;
typedef match_results<char const *> cmatch;

match_results为正则表达式的匹配结果提供一个类似容器的视图,operator[]返回第i个子表达式。

template <typename BidiIter>
struct sub_match : public std::pair
{
    string_type str() const;
    difference_type length() const;
    bool operator!() const;
    int compare(string_type const &) const;//字符串比较
    bool matched;
};

匹配

自由函数regex_match()用来检查一个字符串是否完全匹配一个正则表达式,返回一个bool结果。

bool regex_match(String, basic_regex const & re);
bool regex_match(String, match_results& what, basic_regex const & re);

完全匹配–身份证号码

思路:身份证前六位是地区编码,中间8为是年月日,最后4位数字可能有一个X。
前6位:\d{6}
中8位:年:(1|2)\d{3},月:(0|1)\d,天:[0-3]\d
后四位:\d{3}(X|\d)

//***********************************************************
//FUNCTION:: personal identity match
// C++ 98: \\d{6}((1|2)\\d{3})((0|1)\\d)([0-3]\\d)(\\d{3}(X|\\d))
// C++ 11: R"---\d{6}((1|2)\d{3})((0|1)\d)([0-3]\d)(\d{3}(X|\d))---" Or R"---(\d{6}(1|2)\d{3}(0|1)\d[0-3]\d\d{3}(X|\d))---"
void personalIdentityMatch()
{
    boost::xpressive::cregex Reg = boost::xpressive::cregex::compile("\\d{6}((1|2)\\d{3})((0|1)\\d)([0-3]\\d)(\\d{3}(X|\\d))", boost::xpressive::icase);忽略大小写

    boost::xpressive::cmatch What;
    assert(boost::xpressive::regex_match("999555197001019999", What, Reg));//What保存为()子表达式集合

    for (auto e : What)
    {
        std::cout << "[" << e << "] " ;
    }

    std::cout << std::endl;
    std::cout << "Date: " << What[1] << What[3] << What[5] << std::endl;
}

注意\是转义字符,所以想用其需要再添加一个 \ 。regex_match()要求输入字符串必须要与正则表达式完全匹配。

完全匹配–邮箱

//***********************************************************
//FUNCTION::
void fullMatchMail()
{
    const char* pMail = "[email protected]";
    boost::xpressive::cmatch What;
    boost::xpressive::cregex Reg = boost::xpressive::cregex::compile("(\\w+)@(\\w+).(\\w+)", boost::xpressive::icase);
    assert(boost::xpressive::regex_match(pMail, What, Reg));

    for (auto e : What)
    {
        std::cout << "[" << e << "] " ;
    }
}

查找

regex_search与regex_match相似,但是不要求完全匹配,只要一个子表达式匹配就返回true。
regex_search可以替代string_algo的contains,starts_with,ends_with算法:

std::string Str("readme.TXT");
boost::xpressive::sregex start_reg = boost::xpressive::sregex::compile("^re");
boost::xpressive::sregex end_reg = boost::xpressive::sregex::compile("txt$", boost::xpressive::icase);

assert(boost::xpressive::regex_search(Str, start_reg));
assert(boost::xpressive::regex_search(Str, end_reg ));
assert(boost::xpressive::regex_search(Str, boost::xpressive::cregex::compile("me")));

替换

使用正则表达式匹配字符串,再用指定格式替换:

String regex_replace(String, basic_regex const & re, Format);

Format可以是简单字符串,也可以是一个符合ECMA-262定义的带格式的字符串。注意返回值是一个字符串的拷贝。
regex_replace替换string_algo的修剪和删除算法

//***********************************************************
//FUNCTION::
void regexReplace()
{
    std::string Str("2010 Happy new Year!!!");

    boost::xpressive::sregex Reg1 = boost::xpressive::sregex::compile("^(\\d| )*");
    boost::xpressive::sregex Reg2 = boost::xpressive::sregex::compile("!*$");

    std::cout << boost::xpressive::regex_replace(Str, Reg1, "") << std::endl;
    std::cout << boost::xpressive::regex_replace(Str, Reg2, "") << std::endl;

    Str = boost::xpressive::regex_replace(Str, Reg1, "Y2000 ");
    std::cout << Str << std::endl;
}

迭代

regex_iterator提高类似迭代器的视图(不是容器),可以变量正则表达式的匹配结果。

template <typename BidiIter>
struct regex_iterator
{
    typedef match_results value_type;
    regex_iterator(BidiIter, BidiIter, basic_regex const & ); 
    value_type const & operator*() const;
    value_type const & operator->() const;

    regex_iterator & operator++();
    regex_iterator operator(int);
};

构造函数传入分词区间和正则表达式对象,之后可以反复调用operator++,使用*或者->获取匹配的结果match_results对象

//***********************************************************
//FUNCTION::
void regexIterator()
{
    std::string Str("Power-bomb, power-suit, pOWER-beam, all items \n");
    boost::xpressive::sregex Reg = boost::xpressive::sregex::compile("power-(\\w{4})", boost::xpressive::icase);

    boost::xpressive::sregex_iterator Pos(Str.begin(), Str.end(), Reg);
    boost::xpressive::sregex_iterator End;

    while (Pos != End)
    {
            std::cout << "[" << (*Pos)[0] << "]" ;//operator*返回一个match_results对象
        ++Pos;
    }

    std::cout << std::endl;
}

分词

模板类regex_token_iterator提供了强大的分词迭代器,类基本和regex_iterator一致,区别如下:

...
regex_token_iterator(BidiIter, BidiIter, basic_regex_const &, match_flag_type args);
...
  1. 如果构造时,args传入-1作为参数,将匹配字符串视为分隔符。如果为正数,返回匹配结果的第args个字符串
  2. 解引用返回的是一个sub_match对象,而不是match_results对象。
//***********************************************************
//FUNCTION::
void regexTokenIterator()
{
    char* pStr = "*Link*||+Mario+||Zelda!!!||Metroid";

    //查找所有单词,无视标点符号
    boost::xpressive::cregex Reg = boost::xpressive::cregex::compile("\\w+", boost::xpressive::icase);
    boost::xpressive::cregex_token_iterator Pos(pStr, pStr+strlen(pStr), Reg);
    while (Pos != boost::xpressive::cregex_token_iterator())
    {
        std::cout << "[" << *Pos << "]";
        ++Pos;
    }
    std::cout << std::endl;

    //使用分割正则表达式
    boost::xpressive::cregex SpiltReg = boost::xpressive::cregex::compile("\\|\\|", boost::xpressive::icase);
    Pos = boost::xpressive::cregex_token_iterator(pStr, pStr+strlen(pStr), SpiltReg, -1);
    while (Pos != boost::xpressive::cregex_token_iterator())
    {
        std::cout << "[" << *Pos << "]";
        ++Pos;
    }
    std::cout << std::endl;
}

与regex的区别

接口几乎一致,设计思想不同:

  1. basic_regex的模板参数是迭代器类型,而boost.regex是字符类型
  2. basic_regex必须使用工厂方法compile()创建,而不能直接从一个字符串创建
  3. basic_regex不具有类似std::string的操作接口
  4. basic_regex一些定制功能位于工厂方法compile()中。

【参考资料】
【1】Boost程序库完全开发指南
【2】http://my.oschina.net/lingluonianhua/blog/211788?fromerr=5JdsKJ0k

你可能感兴趣的:(Boost)