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()<<"\n";//錯誤信息
        cout<<e.code()<<endl;//錯誤碼
	}
}
char數組傳參

​ regex_search函數的輸入序列參數可以傳入string或者以'\0'結尾的字符數組,傳入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;                         //輸出錯誤信息
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM