C++11 STL Regex正则表达式与字符串字段解析

  •  简单的日期正则表达式

一个简单的日期解析程序,从yyyy-mm-dd格式的日期字符串中,分别获取年月日。ios

先设置一个简单的正则表达式,4位数字的“年”,1-2位数字的“月”和一样1-2位数字的“日”,中间‘-’做为分隔符。程序代码:正则表达式

#include <iostream>
#include <regex>

using namespace std;

int main() {
    string text = "2018-7-12";
    regex  pattern("[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}");

    smatch results;
    if ( regex_match(text, results, pattern) ) {
        smatch::iterator it = results.begin();
        int i = 0;
        for(; it != results.end(); ++it, ++i)
            cout<<i<<": "<<*it<<endl;
    } else {
        cout << "match failed: " <<text<< endl;
    }
    return 0;
}

执行输出:spa

0: 2018-7-12

smatch类型是一个匹配结果字符串列表,列表中第一个元素永远是执行匹配操做的原始字符串,后续是根据表达式从原始字符串中解析出的子串。code

程序输出结果表示日期字符串与表达式匹配正确,但并无解析出各个日期字段子串。字符串

若是须要解析出子串,则须要对表达式分组。string

  • 表达式分组

分组后的表达式,匹配操做才会以分组位单位输出解析出的子串。将pattern表达式修改以下:it

regex  pattern("([0-9]{4}-[0-9]{1,2}-[0-9]{1,2})");

在这里,整个表达式包含在一个圆括号里,将整个表达式做为一个分组。io

执行后输出:class

0: 2018-7-12
1: 2018-7-12

下标为1的输出项,即为整个表达式分组所匹配到的内容,也就是整个日期字符串,但这尚未达到逐字段分解的目标,须要将分组细分。stream

  • 表达式分组细分

将表达式改成:

regex  pattern("([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})");

其中包含了3个分组(尽管后面两个分组表达式同样,但月份和日期的取值范围并不彻底相同,这里只简单设置)

执行结果:

0: 2018-7-12
1: 2018
2: 7
3: 12

终于达到了日期字段分解的目标。

而后,日期字符串中,月份的表达方式能够是数字,也能够是字母名称,如Jan,Feb,Mar等,那么就须要在表达式中兼容多种格式的日期字符串。

  • 多个格式的月份表达式

当前日期字符串变动名称月份,表达式中增长月份名称:

string text = "2018-Jan-18";
regex  pattern("([0-9]{4})-(([0-9]{1,2})|(Jan|Feb|Mar))-([0-9]{1,2})");

运行结果:

0: 2018-Jan-18
1: 2018
2: Jan
3:
4: Jan
5: 18

在这个表达式中,数字月份做为一个分组,名称月份也是一个分组,二者又合并成一个月份分组,所以匹配月份时,存在这三个分组(一个父分组包含2个子分组),运行输出结果中2-4分别是这三个分组分别对月份匹配的结果,数字月份的子分组表达式没有匹配到,所以输出空字符串。

这样的结果并不使人满意,对于月份来讲,只需输出一项便可,即对于月份匹配,两个子分组不须要单独输出,只须要表示月份的父级分组输出便可。

经过将子分组指定为消极分组(Passive Group)便可。

  • 消极分组

将表达式改成:

regex  pattern("([0-9]{4})-((?:[0-9]{1,2})|(?:Jan|Feb|Mar))-([0-9]{1,2})");

在分组中加上“?:”前缀,即表示该分组位消极分组,在此表达式中,将数字月份和名称月份的子分组都标记为消息分组,运行结果:

0: 2018-Jan-18
1: 2018
2: Jan
3: 18
相关文章
相关标签/搜索