c++ new feature : 正則表達式

正則表達式在c++11後被正式納入標準庫,包含regex_matchregex_searchregex_replace功能模塊,通過正則表達式可以非常方便的對特定模式的字符串進行序列化操作。使用正則表達式之前,需要我們有正則表達式語法基礎,這裏正好有張機票給需要的小夥伴正則表達式

正則表達式與通配符(如windows平臺文件搜索框)區別

通配符主要用來操作文件名 。
正則表達式主要操作文本數據。

regex

爲方便起見,本文的例子統一使用

std::string poem("if you weeped for the missing sunset you would miss\
	all the shining stars. someday,you will find the one,who will wa\
	tch every sunrise with you until the sunset of your life")

作爲匹配源。如果我們想查找在poem中是否有以sun開頭的單詞,我們首先需要定義正則表達式std::regex rgx("sun[^ ]*")或者std::regex seg_rgx("(sun)([^ ]*)")。這兩種定義方法有一點區別,我們稱第二種寫法爲分組寫法,將待匹配部分分隔成sun……兩個部分,如果我們需要對兩個部分精確操作的時候,尤其是在使用regex_replace功能時,可能需要將正則表達式書寫成分組模式,還有一點就是std::cmatchstd::smatch分別是兩個typedef

typedef match_results<const char*> cmatch;
typedef match_results<string::const_iterator> smatch;

regex_search

regex_search作用是查找特定規則的表達式是否在一段文字中,函數定義可以參見文末參考,我不再貼了。

if (std::regex_search(poem, rgx)) {
	std::cout << "regex_search : find a word start with sun int the poem" << std::endl;
}

if (std::regex_search(poem.begin(),poem.end(), rgx)) {
	std::cout << "regex_search : find a word start with sun int the poem" << std::endl;
}

除了上述兩種最基本的使用方法之外,還可以通過正則表達式配合帶有std::cmatchstd::smatch參數的重載版本,獲取匹配細節。

auto temp_poem = poem;
std::cout << "reg search ……" << std::endl;
while (std::regex_search(temp_poem, sm, rgx)) {
	for (auto ref : sm) {
		std::cout << "    " << ref << std::endl;
	}
	temp_poem = sm.suffix().str();
}

temp_poem = poem;
std::cout << "seg_reg search ……" << std::endl;
while (std::regex_search(temp_poem, sm, seg_rgx)) {
	for (auto ref : sm) {
		std::cout << "    " << ref << std::endl;
	}
	temp_poem = sm.suffix().str();
}

使用了分組匹配模式的部分,將匹配細節存入迭代器std::smatch中,由於其定義爲match_results<string::const_iterator>,使用sm.suffix().str()取出匹配之後的語句,重複直到最後一個匹配,結果輸出正則表達式匹配結果與正則表達式各個組匹配的子部分。

reg search ……
    sunset
    sunrise
    sunset
seg_reg search ……
    sunset
    sun
    set
    sunrise
    sun
    rise
    sunset
    sun
    set

可以看出,雖然同樣匹配了三個單詞,使用分組模式的正則表達式進行匹配,我們額外的得到了正則表達式每一組匹配的結果。

regex_match

regex_match函數的使用基本與regex_search相同,爲了更好的區分函數功能,需要另外定義了兩個正則表達式std::regex not_rgx("(?!.*shining)(.*)")std::regex yes_rgx("(.*)(sunset)(.*)(sunrise)(.*)")

if (!std::regex_match(poem.begin(),poem.end(), not_rgx)) {
	std::cout << "regex_match : find a word shining int the poem" << std::endl;
}

if (std::regex_match(poem, yes_rgx)) {
	std::cout << "regex_match : find a ……sunset……sunrise…… format int the poem" << std::endl;
}

if (std::regex_match(poem.begin(), poem.end(), yes_rgx)) {
	std::cout << "regex_match : find a ……sunset……sunrise…… format int the poem" << std::endl;
}

std::regex_match(poem, sm, yes_rgx);
std::regex_match(poem.c_str(), cm, yes_rgx);

std::cout << "cm.size() == sm.size() ? (0 | 1) : " << (cm.size() == sm.size()) << std::endl;

函數的輸出如下,需要注意的是,當使用std::cmatch時,匹配源需要是c風格的const char *

regex_match : find a word shining int the poem
regex_match : find a ……sunset……sunrise…… format int the poem
regex_match : find a ……sunset……sunrise…… format int the poem
cm.size() == sm.size() ? (0 | 1) : 1

regex_replace

很多人在查閱文檔的時候,會對regex_replace這個函數非常困惑,我在第一次查閱參數說明的時候也很疑惑,$1,$2$n到底是幹什麼用的,這就要說到開頭所說的正則表達式的分組模式了,當我們在匹配target中寫出$x的時候,我們寫出的這個正則表達式匹配的組就不進行替換,極端點看,比如我們正則表達式只有兩個組,我們在替換的目標字符串裏面寫了$1, $2,此時替換是沒有效果的,好比你用源字符串替換了源字符串,這樣的設計在我們需要對匹配模式分組中每個組進行操作的時候或者匹配某個部分存在困難,可以先匹配一組內容,再在正則表達式中進行精細劃分。

std::cout << std::regex_replace(poem, rgx, "") << std::endl;
std::cout << std::regex_replace(poem, seg_rgx, "") << std::endl;

std::string replace_poem;
std::regex_replace(std::back_inserter(replace_poem), poem.begin(), poem.end(), rgx, "");
std::cout << "std::back_inserter mode : " << std::endl << replace_poem << std::endl;

std::cout << std::regex_replace(poem, seg_rgx, "$1down") << std::endl;
std::cout << std::regex_replace(poem, seg_rgx, "rain$2") << std::endl;
std::cout << std::regex_replace(poem, seg_rgx, "raindown") << std::endl;
std::cout << std::regex_replace(poem, seg_rgx, "[$1 - $2]", std::regex_constants::format_no_copy) << std::endl;

上面的代碼中,regseg_reg同時找到了sunset-sunrise-sunset三個匹配。而分組模式在這三個匹配裏面又分別匹配了

分組 $1 $2
sunset sun set
sunrise sun rise
sunset sun set

所以當我們分別將目標模式寫爲$1down rain$2 raindown [$1 - $2]作用分別爲

  1. 將三個匹配的sun保留,將set rise set同時替換爲down;
  2. 將三個匹配的set rise set保留,將sun同時替換爲rain;
  3. sunset sunrise sunset同時替換爲raindown;
  4. sun與{set rise set}中間添加連接號,並將匹配文字用中括號括起來。
    可以預想到輸出爲:
if you weeped for the missing  you would miss all the shining stars. someday,you will find the one,who will watch every  with you until the  of your life
if you weeped for the missing  you would miss all the shining stars. someday,you will find the one,who will watch every  with you until the  of your life
std::back_inserter mode :
if you weeped for the missing  you would miss all the shining stars. someday,you will find the one,who will watch every  with you until the  of your life
if you weeped for the missing sundown you would miss all the shining stars. someday,you will find the one,who will watch every sundown with you until the sundown of your life
if you weeped for the missing rainset you would miss all the shining stars. someday,you will find the one,who will watch every rainrise with you until the rainset of your life
if you weeped for the missing raindown you would miss all the shining stars. someday,you will find the one,who will watch every raindown with you until the raindown of your life
[sun - set][sun - rise][sun - set]

代碼

完整代碼見c++正則表達式

參考

cplusplus
cpprefeance
正則表達式

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章