• C++ regex库常用函数及实例


    简介

    regex是C++标准库中用于正则表达式(regular expression)的部分。

    大致有如下常用组件:

    组件名称 作用
    regex 表示有一个正则表达式的类
    regex_match 将一个字符序列与一个正则表达式匹配
    regex_search 寻找第一个与正则表达式匹配的子序列
    regex_replace 使用给定格式替换一个正则表达式
    sregex_iterator 迭代器适配器,内部调用regex_search来遍历一个string中所有匹配的子串
    smatch 容器类,保存在string中搜索的结果
    ssub_match string中匹配的子表达式的结果
    示例

    在下面一个简单的例子里使用一些组件

    #include<regex>
    #include<iostream>
    using namespace std;
    //正则表达式
    void main()
    {
    	string pattern = "^([a-z]|_)[[:alnum:]]+";
        //开头的^表示从字符串开头开始匹配,|表示或,alnum表示字母或数字,+表示至少重复一次
    	regex r(pattern, regex::icase);//初始化正则表达式类,icase表示忽略大小写
    	string s("Asff");
    	smatch results;//用于保存成功匹配的相关信息
    	if (regex_search(s, results, r))
    		cout << results.str() << endl;
    	s="_qwer";
    	if (regex_search(s, results, r))
    		cout << results.str() << endl;
    	s="9sff";
    	if (regex_search(s, results, r))
    		cout << results.str() << endl;
    }
    

    输出如下:

    Asff
    _qwer
    

    ​ 在这个例子里,我们通过regex_search函数,查找第一个与正则表达式匹配的子序列,smatch对象将会保存匹配结果的相关细节。

    异常

    ​ C++的正则表达式并不是由C++编译器解析,而是在运行时由相关库函数进行解析,因此如果正则表达式存在语法错误,程序将会抛出名为regex_error的异常。

    捕获异常并且输出错误信息:

    void fun()
    {
        try{
        	regex r("([[:alpha:]]");        
        }catch(regex_error e)
        {
            cout<<e.what()<<"
    ";//错误信息
            cout<<e.code()<<endl;//错误码
    	}
    }
    
    char数组传参

    ​ regex_search函数的输入序列参数可以传入string或者以''结尾的字符数组,传入string时,使用smatch对象接受匹配成功的相关信息;而传入char*时,如果还使用smatch对象就会编译失败,此时需要使用cmatch对象才能编译成功。

    使用regex迭代器来获取所有匹配

    sregex_iterator的部分操作如下表

    操作 作用
    sregex_iterator it(b,e,r); b,e分别为输入序列的迭代器起始尾后位置,将sregex_iterator对象it定位到输入中第一个匹配的位置
    sregex_iterator it_end; 无参构造函数生成尾后迭代器
    *it 解引用,根据最后一个调用regex_search的结果,返回一个smatch对象的引用
    it-> 间接引用smatch的成员函数
    ++it 在当前匹配位置调用regex_search,并返回递增后的迭代器
    it++ 在当前匹配位置调用regex_search,但返回递增前的迭代器
    it1==it2 如果都是尾后迭代器,则相等。非尾后迭代器如果由相同的输入序列和相同的regex对象构造,则相等
    it1!=it2 不符合相等的情况
    综合示例

    ​ 综合上面的知识,我们可以编写一个提取合法ipv4地址的小程序,其中regex对象pattern中使用\的原因是:一个用于转义'('、')'、'd'(表示整数)等符号,另一个是由于C++中为转义字符,\才表示一个符号。

    #include<regex>
    #include<iostream>
    using namespace std;
    
    bool validSubExepression(const smatch& s)
    {//检查表达式是否合法
    	if (s[1].matched)//如果有左括号,那么要求一定要有匹配的右括号
    		return s[9].matched && s[3].str() == s[5].str() && s[5].str() == s[7].str();//且3个分隔符要相同
    	else//如果没有左括号,那么要求没有右括号
    		return !s[9].matched && s[3].str() == s[5].str() && s[5].str() == s[7].str();
    }
    
    bool overflow(const smatch& s)
    {//ip地址是否溢出
    	for (int i = 2; i <= 8; i++)
    	{
    		int number = atoi(s.str().c_str());
    		if (number > 255)
    			return true;
    	}
    	return false;
    }
    
    int main()
    {
    	string pattern =
    		"(\()?(\d{1,3})([-. ])?(\d{1,3})([-. ])?(\d{1,3})([-. ])?(\d{1,3})(\))?";
    	string ipaddress = "192.168.1.2 (123.233.111.33 114.114.114.114) (8-8.8.8) 7-8-9-10 172 0 0 1 888.224.525.244 192&168&1&1";
    	string fmt = "($2.$4.$6.$8)";//格式化,子表达式2,4,6,8原样输出,其余部分按(...)格式输出
    	try
    	{
    		regex r(pattern);
    		for (sregex_iterator it(ipaddress.begin(), ipaddress.end(), r), end_it; it != end_it; ++it)
    		{
    			if (!overflow(*it))
    			{
    				if (validSubExepression(*it))
    				{
    					cout << "Before format:" << it->str() << endl;
    					cout << "After  format:" << regex_replace(it->str(), r, fmt) << endl << endl;
    				}
    				else
    				{
    					cout << "not valid:" << endl;
    					cout << "Before format:" << it->str() << endl;
    					cout << "After  format:" << regex_replace(it->str(), r, fmt) << endl << endl;
    				}
    			}
    			else
    				cout << "overflow" << endl;
    		}
    	}
    	catch (regex_error e)
    	{
    		cout << "(error code:" << e.code() << ")" << endl;//输出错误代码
    		cout << e.what() << endl;                         //输出错误信息
    	}
    }
    
  • 相关阅读:
    android:versionCode和android:versionName 用途
    ProgressDialog使用总结
    对 Android 开发者有益的 40 条优化建议
    Android TextView换行问题
    Android TextView自动换行文字排版参差不齐的原因
    Python 生成requirement 使用requirements.txt
    PLSQL简介
    python魔法方法详解
    深入了解Token认证的来龙去脉
    数组、链表、栈、队列和STL
  • 原文地址:https://www.cnblogs.com/sgawscd/p/13794818.html
Copyright © 2020-2023  润新知