首頁 > 軟體

C++使用正規表示式的詳細教學

2022-05-26 14:01:39

正規表示式

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

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

RE庫元件

 解釋
regex表示有一個正規表示式的類
regex_match將一個字元序列與一個正規表示式匹配
regex_search尋找第一個與正規表示式匹配的子序列
regex_replace使用給定格式替換一個正規表示式
sregex_iterator迭代器介面卡,呼叫regex_search來遍歷一個string中所有匹配的子串
smatch容器類,儲存在string中搜尋的結果
ssub_matchstring中匹配的子表示式的結果

正規表示式的使用

#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,secondpublic資料成員,指向匹配序列首元素和尾後迭代器
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++正規表示式使用內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com