C++使用正則表達式的詳細教程

正則表達式

正則表達式(regular expression)是一種描述字符序列的方法,是一種極其強大的計算工具。

C++正則表達式庫(RE庫)定義在<regex>中,它包含多個組件。

RE庫組件

  解釋
regex 表示有一個正則表達式的類
regex_match 將一個字符序列與一個正則表達式匹配
regex_search 尋找第一個與正則表達式匹配的子序列
regex_replace 使用給定格式替換一個正則表達式
sregex_iterator 迭代器適配器,調用regex_search來遍歷一個string中所有匹配的子串
smatch 容器類,保存在string中搜索的結果
ssub_match string中匹配的子表達式的結果

正則表達式的使用

#include <regex>
void test()
{
    //查找不是在字符c之後的ei組合存在的單詞
	string pattern("[^c]ei");
	pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]]*";
	regex r(pattern);
	smatch results;
	string test_str("receipt freind theif receive");
	if (regex_search(test_str, results, r))
		cout << results.str() << endl;//freind
}

regex迭代器類型

上面的程序隻能查找第一個匹配到的單詞,如果想獲得所有匹配,可以使用sregex_iterator

for (sregex_iterator it(test_str.begin(),test_str.end(),r), end_it;it != end_it;++it) {
		cout << it->str() << endl;
}

輸出:

freind
theif

for循環中定義瞭兩個迭代器,it負責尋找匹配的單詞,end_it是一個空迭代器,起到尾後迭代器的作用。

解引用迭代器會得到一個匹配結果的smatch對象。

除瞭得到匹配的smatch對象以外,還可以得到其上下文。

for (sregex_iterator it(test_str.begin(),test_str.end(),r), end_it;it != end_it;++it) {
	auto pos = it->prefix().length();
	pos = pos > 40 ? pos - 40 : 0;
	cout << it->prefix().str().substr(pos)
		<< "[ " << it->str() << " ]"
		<< it->suffix().str().substr(0, 40)
		<< endl;
}

輸出:

receipt [ freind ] theif receive
 [ theif ] receive

使用prefix和suffix函數可以得到匹配之前和之後的ssub_match對象。

smatch相關操作

  解釋
m.ready() 若已通過regex_search或regex_match設置瞭m,則返回true;否則返回false
m.size() 如果匹配失敗,返回0;否則返回最近一次匹配的正則表達式中子表達式的數目
m.empty() 若m.size()==0,返回true
m.prefix() 一個ssub_match對象,表示當前匹配之前的序列
m.suffix() 一個ssub_match對象,表示當前匹配之後的部分
m.format() 格式化輸出
m.length(n) 第n個匹配的子表達式的大小
m.position(n) 第n個子表達式距序列開始的距離
m.str(n) 第n個子表達式匹配的string
m[n] 對應第n個子表達式的ssub_match對象
m.begin(),m.end() m中sub_match元素范圍的迭代器
m.cbegin(),m.cend() m中sub_match元素范圍的常量迭代器

這些操作也適用於cmatch、wsmatch、wcmatch和對應的子匹配對象。

子表達式

正則表達式中的模式通常包含一個或多個子表達式(subexpression)。

一個子表達式是模式的一部分,本身也具有意義。

正則表達式語法同常用小括號表示子表達式。

eg: 可以使用子表達式來匹配文件擴展名

regex r("([[:alnum:]]+)\\.(cpp|cxx|cc)$");

現在模式中有兩個小括號表示的子表達式:

  • ([[:alnum:]]+) 匹配一個或多個數字字母序列
  • (cpp|cxx|cc) 匹配cpp或cxx或cc等擴展名

通過使用str(n)來打印子表達式

if (regex_search(filename, results, r))
		cout << results.str(1) << endl;//打印第一個子表達式

參數0代表整個對應的匹配,參數1表示第一個子表達式。

如,foo.cpp中,results.str(0)將保存foo.cpp,results.str(1)將保存foo。

子表達式用於數據驗證

子表達式的一個常見用途是驗證必須匹配特定格式的數據。

eg:匹配聯通號碼

中國聯通號段:130、131、132、145、155、156、166、175、176、185、186、196

使用開源工具Regulex實現正則表達式設計可視化。

void test02()
{
	//匹配聯通號碼
	string UnicomNumber("\\b(1)(3[0-2]|[4578]5|[5-9]6)(\\d{4})(\\d{4})\\b");
	regex r(UnicomNumber);
	string testNumbers("130123456789 23112345678 7602125 1320000 16512345678 14512345678 17612345678");
	for (sregex_iterator it(testNumbers.begin(), testNumbers.end(), r), end_it;it != end_it;++it) {
		cout << it->str() << endl;	
	}
}

結果:

1451234567817612345678

解釋:

在模式UnicomNumber中,有4個子表達式

子表達式索引號 子表達式 含義
子表達式1 (1) 匹配1
子表達式2 (3[0-2]|[4578]5|[5-9]6) 匹配30/31/32/45/55/75/85/56/66/76/86/96
子表達式3 (\d{4}) 匹配任意4個數字
子表達式4 (\d{4}) 匹配任意4個數字

此外,"\b"匹配單詞邊界,可以理解為空格與單詞的分界線。"\d"匹配任意數字。[]內表示多選一,{n}表示匹配n個,子表達式內"|"表示或。

並且,在正則表達式語法中"\“具有轉義作用,在C++中也有轉義作用,因此,為瞭得到正則表達式中的”\",需要在string中額外加一個"\"。所以我們的表達式中會有"\\b"和"\\d"。

在正則匹配過程中,迭代器查找每一個號碼,進行分析

號碼 分析
130123456789 多瞭一位數字,單詞邊界匹配失敗
23112345678 子表達式1匹配失敗
7602125 子表達式1匹配失敗
1320000 子表達式3匹配失敗(或者說是邊界匹配失敗?)
16512345678 子表達式2匹配失敗
14512345678 匹配成功
17612345678 匹配成功

子匹配操作

ssub_match的相關操作

  解釋
matched 一個public bool成員,指出此ssub_match是否匹配瞭
first,second public數據成員,指向匹配序列首元素和尾後迭代器
length() 匹配的大小
str() 匹配的string
s = ssub 將ssub_match對象轉化為string對象

添加一段代碼,測試一下matched成員

for (sregex_iterator it(testNumbers.begin(), testNumbers.end(), r), end_it;it != end_it;++it) {
	cout << it->str() << endl;	
	cout << "\t" << (*it)[4].matched << endl;
}

結果

14512345678
        1
17612345678
        1

這裡的matched為true表示匹配到瞭,當然,UnicomNumber的子表達式並非是可選匹配的(用"?"跟在一個表達式後表示可以有1個或0個該表達式),所以它的四個子表達式全部匹配到瞭,若是可選表達式,可能會出現matched為false的情況。

regex_replace

正則表達式不僅用在查找給定序列方面,當我們想將查找到的序列替換為另一個序列時,可使用regex_replace。

eg:格式化輸出電話號碼

void test03()
{
	string UnicomNumber("\\b(1)(3[0-2]|[4578]5|[5-9]6)(\\d{4})(\\d{4})\\b");
	regex r(UnicomNumber);
	string fmt = "$1$2 $3 $4";
	string number = "14512345678";
	cout << regex_replace(number,r,fmt) << endl;
}

結果:

145 1234 5678

解釋:

使用"$"後跟子表達式的索引號來表示一個特定的子表達式。

在"$1$2 $3 $4"中,希望子表達式1和2在一起,跟子表達式3和4之間都使用空格(" ")隔開。

參考資料

《C++ Primer 第5版》

總結 

到此這篇關於C++使用正則表達式的文章就介紹到這瞭,更多相關C++正則表達式使用內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: