zoukankan      html  css  js  c++  java
  • C++ boost 正则表达式用法

    什么是正则表达式?正则表达式是一种用来描述一定数量文本的模式。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.]+)$");

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



    regex_match

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

    if (regex_match(str, m, re))

    {

        ...

    }

    str是一个字符串,可以是stringwstringchar *或者wchar_t *

    mmatch_results,它通过引用传入参数,来保存匹配的结果,m要和str的类型匹配,可以是smatchwsmatchcmatchwcmatch,用来分别对应stringwstringchar *或者wchar_t*str

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

    strmre的类型如下:

    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保存了匹配的结果;返回falsem未定义。

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

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

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

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

    m.prefix()m.suffix()

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

    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 表示第nsub-expression是否在字符串中存在。整个regex匹配,但是sub_exp可能匹配的是空的,例如”(a*)”就有可以匹配空。

    m[n].firstm[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是从左往右匹配,而且尽量匹配长的字串。 

  • 相关阅读:
    混合背包
    二维背包
    0/1背包问题(DP)
    冒泡排序
    快速排序
    最长上升子序列
    二分查找
    n后问题
    crontab 定时任务
    删除以某字符串开头的表
  • 原文地址:https://www.cnblogs.com/wubiyu/p/1344093.html
Copyright © 2011-2022 走看看