c++ 正则匹配std::regex的使用

0.文章主旨

本文简单介绍 关于 正则匹配 std::regex 的使用。

1.关注点

(1)编译正则表达式
(2)正则匹配运算 & ()分组的位置
(3)中文 & wchar :
① 中文单字的位置
② 打印
③ 读取文件

2.简单介绍

2.1 语法简介

2.1.1 语法-头文件

2.1.1.1 char类型
#include <regex>

using std::regex;
using std::cmatch;
using std::regex_match;
using std::regex_search;

*注:后两个是函数

2.1.1.2 wchar类型
using std::wregex;
using std::wcmatch;

*注:使用方法与char类型的相同(注意 wchar_t[] 字面值形如 L"abc"),函数仍使用 std::regex_match() 或 std::regex_search()。

2.1.2 语法-编译正则表达式

regex rule(rule_str);

*注:rule_str 是正则表达式string

2.1.3 语法-创建一个用于存储正则匹配结果的中间变量

cmatch match_rslt;

使用这个变量可以获取更多正则匹配的细节

2.1.4 语法-正则匹配运算

  • 文本全匹配
regex_match(line.c_str(), match_rslt, rule)
  • 文本局部匹配
regex_search(line.c_str(), match_rslt, rule)

*注:
(1)line是实际待匹配的文本,
(2)match_rslt用于存储详细的匹配结果(如果只考虑是否匹配,不考虑匹配细节可以不要这个参数),
(3)rule是之前编译好的正则表达式(比如:使用一个静态的正则表达式文本文件作为预设的资源,此时可以预先再程序初始化时编译好正则表达式,然后反复使用,节省编译时间)。

2.1.5 语法-获取匹配结果

2.1.5.1 如何判断:是否匹配到了?

关注 regex_match() 和 regex_search() 的返回值

2.1.5.2整体匹配
  1. 整体匹配-起始位置
match_rslt.position()
  1. 整体匹配-整体匹配的长度
match_rslt.length()
  1. 整体匹配-匹配的文本内容

A) 方法1

match_rslt.str()

B) 方法2

match_rslt[0].str()

*注:
a) 注意先判断是否匹配上(或判空);
b) 可以用cout打印,甚至直接打印 match_rslt[0];
c) 注意 wchar类型 时,不能这样打印!!!

2.1.5.3 局部匹配
  1. 局部匹配-分组个数
match_rslt.size()-1

*注:
(1)-1是因为第一个元素是整体匹配的结果
(2)这个数量相当于 正则表达式中()的数量

  1. 局部匹配-分组长度
    首先假设我们这样遍 历匹配到的分组:
for(auto& elm: match_rslt)

elm 相当于 match_rslt[i]
接着我们可以这样查看分组长度:

elm.length()
  1. 局部匹配-分组起始位置计算
elm.first-match_rslt[0].first+match_rslt.position()

解析:
(1)elm.first 是一个地址,也就是这个分组在原输入序列的起始索引
(2)match_rslt[0].first 相当于 整体匹配在原序列的起始地址,我们做差值自然可以得到当前分组相对于整体匹配的索引
(3)最后我们加上 整体匹配在原始序列中的起始索引,最终得到的是 当前分组相对于原始序列 的起始索引

举例:
正则表达式:“你好[,。!]?我叫.{1,4}[,。!]?(请多指教|)$”
输入序列:“你好我叫甲乙丙,请多指教”
整体匹配:“你好我叫甲乙丙,请多指教”, start=0, len=12
分组匹配(只有一个分组):“请多指教”, start=8, len=4

*注:
(1)上面这个例子是用 wchar 正则匹配的
(2).{1,4}表示 单字到四字 的通配,在char条件下基本上只能匹配单字,但是wchar可以匹配到四字

  1. 局部匹配-分组内容
  • 对于 char
    方法1:
elm.str()

*注:
(1)可以用cout打印出来,甚至可以直接打印 elm
(2)对于wchar 的打印,不推荐使用类似于:wcout<<elm.str()<<endl; 的方式。

方法2:

line.substr(start,len)
  • 对于 wchar
    (1)取出 wstring分组 的方法与char相同(elm.str() 或 line.substr(start,len)),
    (2)但是打印不推荐使用类似于:wcout<<elm.str()<<endl; 的方式
    (3)打印的推荐方式(先转成string,在用cout):
cout<<"1===>"<<to_byte_string(elm.str())<<endl;

*注:
to_byte_string() 这个函数是网上抄来的,用于将wstring转为string,详细代码在 小节“3.使用样例”里面有。

3.使用样例

#include <iostream>
#include <fstream>

#include <string>
#include <regex>

#include <locale>
#include <codecvt>
#include <Windows.h>

using std::cout;
using std::endl;
using std::ifstream;

using std::string;

using std::regex;
using std::cmatch;
using std::regex_match;
using std::regex_search;

using std::wcout;
using std::wstring;
using std::wregex;
using std::wcmatch;
using std::wifstream;

// === functions ===================
std::string to_byte_string(const std::wstring& input)
{
    //std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
    return converter.to_bytes(input);
}

std::wstring StringToWString(const std::string& str)
{
    int num = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
    wchar_t *wide = new wchar_t[num];
    MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, wide, num);
    std::wstring w_str(wide);
    delete[] wide;
    return w_str;
}

void show_wstr(const wstring& line, const string& split_tag = ", ", const string& link_tag=":") {
    for(int i=0; i<line.size(); ++i) {
        cout<<i<<link_tag<<to_byte_string(wstring({line[i]}))<<split_tag;
    }
    cout<<endl;
}


void try_regex(const string& rule_str, const string& line, const string& end_line = "\n") {
    regex rule(rule_str);
    cmatch match_rslt;

    if (regex_match(line.c_str(), match_rslt, rule)) {
        // 整句匹配
        cout<<"MATCH: line(\""<<line<<"\") MATCH rule(\""<<rule_str<<"\")."<<endl;
        int i = 0;
        for(auto& elm: match_rslt) {
            cout<<"match_part["<<i<<"]: \""<<elm
                <<"\", start="<<elm.first-match_rslt[0].first+match_rslt.position() // 匹配到的部分 起始位置计算 !!!
                <<", len="<<elm.length()<<endl;
            ++i;
        }
        cout<<"match poi: "<<match_rslt.position()<<endl;
    } else if (regex_search(line.c_str(), match_rslt, rule)) {
        // 局部匹配
        cout<<"SEARCH: line(\""<<line<<"\") SEARCH rule(\""<<rule_str<<"\")."<<endl;
        int i = 0;
        for(auto& elm: match_rslt) {
            cout<<"match_part["<<i<<"]: \""<<elm
                <<"\", start="<<elm.first-match_rslt[0].first+match_rslt.position()
                <<", len="<<elm.length()<<endl;
            ++i;
        }
        cout<<"match poi: "<<match_rslt.position()<<endl;
    } else {
        // 不匹配
        cout<<"NOT MATCH: line(\""<<line<<"\") NOT match rule(\""<<rule_str<<"\")!"<<endl;
    }
    cout<<"match part num: "<<match_rslt.size()<<endl;
    cout<<end_line;
}

void try_wregex(const wstring& rule_wstr, const wstring& line, const string& end_line = "\n") {
    wregex rule(rule_wstr);
    wcmatch match_rslt;

    if (regex_match(line.c_str(), match_rslt, rule)) {
        // 整句匹配
        cout<<"MATCH: line(\""<<to_byte_string(line)<<"\") MATCH rule(\""<<to_byte_string(rule_wstr)<<"\")."<<endl;
        int i = 0;
        for(auto& elm: match_rslt) {
            size_t start = elm.first-match_rslt[0].first+match_rslt.position();
            size_t len = elm.length();
            cout<<"match_part["<<i<<"]: \""<<to_byte_string(line.substr(start,len)) // wstring 的elm 没法直接打印 !!!
                <<"\", start="<<start
                <<", len="<<len<<endl;
            ++i;
        }
        cout<<"match poi: "<<match_rslt.position()<<endl;
    } else if (regex_search(line.c_str(), match_rslt, rule)) {
        // 局部匹配
        cout<<"SEARCH: line(\""<<to_byte_string(line)<<"\") SEARCH rule(\""<<to_byte_string(rule_wstr)<<"\")."<<endl;
        int i = 0;
        for(auto& elm: match_rslt) {
            size_t start = elm.first-match_rslt[0].first+match_rslt.position();
            size_t len = elm.length();
            cout<<"match_part["<<i<<"]: \""<<to_byte_string(line.substr(start,len))
                <<"\", start="<<start
                <<", len="<<len<<endl;
            ++i;
        }
        cout<<"match poi: "<<match_rslt.position()<<endl;
    } else {
        // 不匹配
        cout<<"NOT MATCH: line(\""<<to_byte_string(line)<<"\") NOT match rule(\""<<to_byte_string(rule_wstr)<<"\")!"<<endl;
    }
    cout<<"match part num: "<<match_rslt.size()<<endl;
    cout<<end_line;
}

void load_rule_txt_and_test(const char* pth, const string& in_str) {
    ifstream f(pth);
    string rule_line;
    while(getline(f,rule_line)){
        if (rule_line.size()) {
            try_regex(rule_line, in_str);
        }
    }

    f.close();
}

void load_wrule_txt_and_test(const char* pth, const wstring& in_wstr) {
    ifstream f(pth);
    string rule_line;
    while(getline(f,rule_line)){
        if (rule_line.size()) {
            cout<<"rule now: "<<rule_line<<endl;
            try_wregex(StringToWString(rule_line), in_wstr); // 读取 中文正则文件, 采用: 先读取string,再转为wstring的方式 !!!
        }
    }

    f.close();
}

// === main ==========================
int main() {
    // 1. match & search
    // string rule2 = "[0-9]+([a-z]+)([A-Z]+)";
    // try_regex(rule2, "123ab"); // not match
    // try_regex(rule2, "ab123abABCD45"); // search
    // try_regex(rule2, "123abABCD");// match
    // cout<<"======================"<<endl;

    // 2. wstring
    // wstring wrule1 = L"你好[,。!]?我叫.{1,4}[,。!]?(请多指教|)$";
    // try_wregex(wrule1, L"你好我叫甲乙丙,请多指教");
    // try_wregex(wrule1, L"你好我叫12345,请多指教");

    // 3. get regex rules by open file
    // const char* pth = "D:\\learn\\cpp\\code\\regex_rule_for_test.txt";
    // load_rule_txt_and_test(pth, "你好我叫123,请多指教");
    // cout<<"-------------------"<<endl;
    // load_rule_txt_and_test(pth, "你好我叫甲乙丙,请多指教");
    // cout<<"======================"<<endl;

    // 4. get regex rules (zn_ch mode) by open file
    const char* pth = "D:\\learn\\cpp\\code\\regex_rule_for_test.txt";
    load_wrule_txt_and_test(pth, L"你好我叫甲乙丙,请多指教");
    cout<<"-------------------"<<endl;
    load_wrule_txt_and_test(pth, L"你好我叫12345,请多指教");
    cout<<"======================"<<endl;

    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值