C++正则表达式(regex_match、regex_search与regex_replace)

1 转义字符

cout << regex_match("123", regex("\d+")) << endl;    //结果为0,需要转义字符'\'
cout << regex_match("123", regex("\\d+")) << endl;    //结果为1,完全匹配
  • \d:匹配一个数字字符;
  • + :匹配一次或多次;
  • *  :匹配0次或多次;

2 regex_match

2.1 基本概念

match是全文匹配,即要求整个字符串符合匹配规则。

cout << regex_match("123", regex("\\d")) << endl;        //结果为0
cout << regex_match("123", regex("\\d+")) << endl;        //结果为1

上述方法返回值为bool值,主要用于if条件表达式中。

2.2 匹配结果

更多的时候我们希望能够获得匹配结果(字符串),对结果进行操作。这时就需要对匹配结果进行存储,共有两种存储方式。

match_results<string::const_iterator> result;
smatch result;            //推荐

第二种方式使用起来更简洁、方便,推荐使用。

2.3 实例
下面看一个match方法匹配的实例,看看实际应用:

string str = "Hello_2018";
smatch result;
regex pattern("(.{5})_(\\d{4})");    //匹配5个任意单字符 + 下划线 + 4个数字

if (regex_match(str, result, pattern))
{
    cout << result[0] << endl;        //完整匹配结果,Hello_2018
    cout << result[1] << endl;        //第一组匹配的数据,Hello
    cout << result[2] << endl;        //第二组匹配的数据,2018
    cout<<"结果显示形式2"<<endl;
    cout<< result.str() << endl;    //完整结果,Hello_2018
    cout<< result.str(1) << endl;    //第一组匹配的数据,Hello
    cout << result.str(2) << endl;    //第二组匹配的数据,2018
}

//遍历结果
for (int i = 0; i < result.size(); ++i)
{
    cout << result[i] << endl;
}

result[]与result.str()这两种方式能够获得相同的值,我更喜欢用数组形式的。
在匹配规则中,以括号()的方式来划分组别,实例中的规则共有两个括号,所以共有两组数据。

3 regex_search


3.1 基本概念
search是搜索匹配,即搜索字符串中存在符合规则的子字符串。
match与search一比较便知:

cout << regex_match("123", regex("\\d")) << endl;        //结果为0
cout << regex_search("123", regex("\\d")) << endl;        //结果为1

3.2 实例
直接看例子:

string str = "Hello 2018, Bye 2017";
smatch result;
regex pattern("\\d{4}");    //匹配四个数字

//迭代器声明
string::const_iterator iterStart = str.begin();
string::const_iterator iterEnd = str.end();
string temp;
while (regex_search(iterStart, iterEnd, result, pattern))
{
    temp = result[0];
    cout << temp << " ";
    iterStart = result[0].second;    //更新搜索起始位置,搜索剩下的字符串
}

输出结果:2018 2017

只需要利用迭代器就可以很轻松的访问到所有匹配的结果值。

4 regex_replace


4.1 基本概念
replace是替换匹配,即可以将符合匹配规则的子字符串替换为其他字符串。

string str = "Hello_2018!";
regex pattern("Hello");    
cout << regex_replace(str, pattern, "") << endl;    //输出:_2018,将Hello替换为""
cout << regex_replace(str, pattern, "Hi") << endl;    //输出:Hi_2018,将Hello替换为Hi

4.2 扩展
除了直接替换以外,还有可以用来调整字符串内容(缩短、顺序等)。

string str = "Hello_2018!";    
regex pattern2("(.{3})(.{2})_(\\d{4})");                //匹配3个任意字符+2个任意字符+下划线+4个数字
cout << regex_replace(str, pattern2, "$1$3") << endl;    //输出:Hel2018,将字符串替换为第一个和第三个表达式匹配的内容
cout << regex_replace(str, pattern2, "$1$3$2") << endl;    //输出:Hel2018lo,交换位置顺序
$n用于表示第n组匹配数据(组这个概念在文章前面部分提到过),所以我们可以利用这种方式来将字符串的内容进行调整。

5 匹配忽略大小写


有时我们希望能够匹配的时候忽略大小写,这时候就要用到Regex的语法选项了。

cout << regex_match("aaaAAA", regex("a*", regex::icase)) << endl;    //结果为1
cout << regex_match("aaaAAA", regex("a*")) << endl;                    //结果为0

regex::icase:匹配时忽略大小写。

6 帮助网站


附上两个写正则表达式常用到的网站

在线正则表达式验证 https://tool.oschina.net/regex/
https://regexper.com/(显示正则表达式匹配结构)

boost:

问题的提出:

Boost.Regex作为Boost对正则表达式的实践,是C++开发中常用模式匹配工具。但在这次使用过程中发现,它他对中文的支持并不好。当我们指定/w匹配时,包含“数”或“节”等字的字符串就会出现匹配失败的问题。

解决方案:

思路:把字符都转换成宽字符,然后再匹配。
需要用到以下和宽字符有关的类:
1、wstring:
作为STL中和string相对应的类,专门用于处理宽字符串。方法和string都一样,区别是value_type是wchar_t。wstring类的对象要赋值或连接的常量字符串必须以L开头标示为宽字符。
2、wregex:
和regex相对应,专门处理宽字符的正则表达式类。同样可以使用regex_match()和regex_replace()等函数。regex_match()的结果需要放在wsmatch类的对象中。
字符和宽字符的相互转换:
1、RTL的方法
//把字符串转换成宽字符串
    setlocale( LC_CTYPE, "" );  // 很重要,没有这一句,转换会失败。
    int iWLen= mbstowcs( NULL, sToMatch.c_str(), sToMatch.length() );  // 计算转换后宽字符串的长度。(不包含字符串结束符)
    wchar_t *lpwsz= new wchar_t[iWLen+1];
    int i= mbstowcs( lpwsz, sToMatch.c_str(), sToMatch.length() );  // 转换。(转换后的字符串有结束符)
    wstring wsToMatch(lpwsz);
    delete []lpwsz;
//把宽字符串转换成字符串,输出使用
    int iLen= wcstombs( NULL, wsm[1].str().c_str(), 0 ); // 计算转换后字符串的长度。(不包含字符串结束符)
    char *lpsz= new char[iLen+1];
    int i= wcstombs( lpsz, wsm[1].str().c_str(), iLen ); // 转换。(没有结束符)
    lpsz[iLen] = '/0';
    string sToMatch(lpsz);
    delete []lpsz;
2、Win32 SDK的方法
//把字符串转换成宽字符串
    int iWLen= MultiByteToWideChar( CP_ACP, 0, sToMatch.c_str(), sToMatch.size(), 0, 0 ); // 计算转换后宽字符串的长度。(不包含字符串结束符)
    wchar_t *lpwsz= new wchar_t [iWLen+1];
    MultiByteToWideChar( CP_ACP, 0, sToMatch.c_str(), sToMatch.size(), lpwsz, iWLen ); // 正式转换。
    wsz[iWLen] = L'/0';
//把宽字符串转换成字符串,输出使用
    int iLen= WideCharToMultiByte( CP_ACP, NULL, wsResult.c_str(), -1, NULL, 0, NULL, FALSE ); // 计算转换后字符串的长度。(包含字符串结束符)
    char *lpsz= new char[iLen];
    WideCharToMultiByte( CP_OEMCP, NULL, wsResult.c_str(), -1, lpsz, iLen, NULL, FALSE); // 正式转换。
    sResult.assign( lpsz, iLen-1 ); // 对string对象进行赋值。

示例:

通过以下程序我们可以看到,对字符串做/w匹配时,某些字会引起匹配失败。通过把字符串转换成宽字符串尝试解决这个问题。

#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
using std::wstring;
#include <locale>

#include "boost/tr1/regex.hpp"
using namespace boost;

void MatchWords(string sToMatch)
{
    regex rg("(//w*)");
    smatch sm;
    regex_match( sToMatch, sm, rg );
    cout << "匹配结果:" << sm[1].str() << endl;
}

void MatchWords(wstring wsToMatch)
{
    wregex wrg(L"(//w*)");
    wsmatch wsm;
    regex_match( wsToMatch, wsm, wrg );

    int iLen= wcstombs( NULL, wsm[1].str().c_str(), 0 );
    char *lpsz= new char[iLen+1];
    int i= wcstombs( lpsz, wsm[1].str().c_str(), iLen );
    lpsz[iLen] = '/0';

    string sToMatch(lpsz);
    delete []lpsz;
    cout << "匹配结果:" << sToMatch << endl;
}

void main()
{
    string sToMatch("数超限");
    MatchWords( sToMatch );
    sToMatch = "节点数目超限";
    MatchWords( sToMatch );

    setlocale( LC_CTYPE, "" );
    int iWLen= mbstowcs( NULL, sToMatch.c_str(), sToMatch.length() );
    wchar_t *lpwsz= new wchar_t[iWLen+1];
    int i= mbstowcs( lpwsz, sToMatch.c_str(), sToMatch.length() );

    wstring wsToMatch(lpwsz);
    delete []lpwsz;
    MatchWords( wsToMatch );
}

编译执行程序后输出:
   匹配结果:数超限
    匹配结果:
    匹配结果:节点数目超限
第一行显示“数超限”匹配成功。但第二行“节点数超限”没有匹配到任何字符。只有转换成宽字符串之后才能够对“节点数超限”成功进行/w匹配。
————————————————

 

std:

#include <iostream>
#include <regex>
#include <tchar.h> //_T
using namespace std;


int main()
{
    /*string s0 = "学正楼";
    cout << s0[0] ;
    cout << s0[1] << endl;
*/

    //wcout.imbue(locale("chs", locale::ctype));  //据说有平台问题
    //wstring s1 = L"学正楼";
    //wcout << s1[0];

    std::locale loc("");
    std::wcout.imbue(loc);

    std::wstring text(L"我的IP地址是:109.168.0.1.");
    std::wstring newIP(L"127.0.0.1");
    std::wstring regString(L"(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)");

    // 表达式选项 - 忽略大小写  
    std::regex_constants::syntax_option_type fl = std::regex_constants::icase;

    // 编译一个正则表达式语句  
    std::wregex regExpress(regString, fl);

    // 保存查找的结果  
    std::wsmatch ms;

    // 判断是否全行匹配  
    if (std::regex_match(text, ms, regExpress))
    {
        std::wcout << L"正则表达式:" << regString << L"匹配:" << text << L"成功." << std::endl;
    }
    else
    {
        std::wcout << L"正则表达式:" << regString << L"匹配:" << text << L"失败." << std::endl;
    }

    // 查找  
    if (std::regex_search(text, ms, regExpress))
    {
        std::wcout << L"正则表达式:" << regString << L"查找:" << text << L"成功." << std::endl;
        for (size_t i = 0; i < ms.size(); ++i)
        {
            std::wcout << L"第" << i << L"个结果:\"" << ms.str(i) << L"\" - ";
            std::wcout <<L"起始位置:" << ms.position(i) << L"长度" << ms.length(i) << std::endl;
        }
        std::wcout << std::endl;

        // 替换1  
        text = text.replace(ms[0].first, ms[0].second, newIP);
        std::wcout << L"替换1后的文本:" << text << std::endl;
    }
    else
    {
        std::wcout << L"正则表达式:" << regString << L"查找:" << text << L"失败." << std::endl;
    }

    // 替换2  
    newIP = L"255.255.0.0";
    std::wstring newText = std::regex_replace(text, regExpress, newIP);
    std::wcout << L"替换2后的文本:" << newText << std::endl;

    // 结束  
    std::wcout << L"按回车键结束...";
    std::wcin.get();
    return 0;


    getchar();
    return 0;
}
#include "regex.hpp"
#include <regex>
#include <string>
#include <vector>
#include <iostream>

int test_regex_match()
{
    std::string pattern{ "\\d{3}-\\d{8}|\\d{4}-\\d{7}" }; // fixed telephone
    std::regex re(pattern);

    std::vector<std::string> str{ "010-12345678", "0319-9876543", "021-123456789"};

    /* std::regex_match:
        判断一个正则表达式(参数re)是否匹配整个字符序列str,它主要用于验证文本
        注意,这个正则表达式必须匹配被分析串的全部,否则返回false;如果整个序列被成功匹配,返回true
    */

    for (auto tmp : str) {
        bool ret = std::regex_match(tmp, re);
        if (ret) fprintf(stderr, "%s, can match\n", tmp.c_str());
        else fprintf(stderr, "%s, can not match\n", tmp.c_str());
    }

    return 0;
}

int test_regex_search()
{
    std::string pattern{ "http|hppts://\\w*$" }; // url
    std::regex re(pattern);

    std::vector<std::string> str{ "http://blog.csdn.net/fengbingchun", "https://github.com/fengbingchun",
        "abcd://124.456", "abcd https://github.com/fengbingchun 123" };

    /* std::regex_search:
        类似于regex_match,但它不要求整个字符序列完全匹配
        可以用regex_search来查找输入中的一个子序列,该子序列匹配正则表达式re
    */

    for (auto tmp : str) {
        bool ret = std::regex_search(tmp, re);
        if (ret) fprintf(stderr, "%s, can search\n", tmp.c_str());
        else fprintf(stderr, "%s, can not search\n", tmp.c_str());
    }

    return 0;
}

int test_regex_search2()
{
    std::string pattern{ "[a-zA-z]+://[^\\s]*" }; // url
    std::regex re(pattern);

    std::string str{ "my csdn blog addr is: http://blog.csdn.net/fengbingchun , my github addr is: https://github.com/fengbingchun " };
    std::smatch results;
    while (std::regex_search(str, results, re)) {
        for (auto x : results)
            std::cout << x << " ";
        std::cout << std::endl;
        str = results.suffix().str();
    }

    return 0;
}

int test_regex_replace()
{
    std::string pattern{ "\\d{18}|\\d{17}X" }; // id card
    std::regex re(pattern);

    std::vector<std::string> str{ "123456789012345678", "abcd123456789012345678efgh",
        "abcdefbg", "12345678901234567X" };
    std::string fmt{ "********" };

    /* std::regex_replace:
        在整个字符序列中查找正则表达式re的所有匹配
        这个算法每次成功匹配后,就根据参数fmt对匹配字符串进行替换
    */

    for (auto tmp : str) {
        std::string ret = std::regex_replace(tmp, re, fmt);
        fprintf(stderr, "src: %s, dst: %s\n", tmp.c_str(), ret.c_str());
    }

    return 0;
}

int test_regex_replace2()
{
    // reference: http://www.cplusplus.com/reference/regex/regex_replace/
    std::string s("there is a subsequence in the string\n");
    std::regex e("\\b(sub)([^ ]*)");   // matches words beginning by "sub"

    // using string/c-string (3) version:
    std::cout << std::regex_replace(s, e, "sub-$2");

    // using range/c-string (6) version:
    std::string result;
    std::regex_replace(std::back_inserter(result), s.begin(), s.end(), e, "$2");
    std::cout << result;

    // with flags:
    std::cout << std::regex_replace(s, e, "$1 and $2", std::regex_constants::format_no_copy);
    std::cout << std::endl;

    return 0;
}

 

  • 5
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值