C++與正規表示式入門 - IT人

文章推薦指數: 80 %
投票人數:10人

C++中正規表示式的API基本上都位於標頭檔案中。

部分程式碼為了簡化書寫,都已經預設做了以下操作: #include  ... Togglenavigation IT人 IT人 C++與正規表示式入門 RioTian發表於 2020-07-23 C++ 什麼是正規表示式? 正規表示式是一組由字母和符號組成的特殊文字,當你想要判斷許多字串是否符合某個特定格式;當你想在一大段文字中查詢出所有的日期和時間;當你想要修改大量日誌中所有的時間格式,在這些情況下,正規表示式都能幫上忙。

簡單來說,正規表示式描述了一系列規則,通過這些規則,可以在字串中找到相關的內容,規則使得搜尋的能力更加強大。

匹配的過程由正規表示式引擎完成。

開發者通常不需要關心正規表示式引擎的實現細節,直接使用其提供的能力即可。

大家可以先想象你正在寫一個應用,然後你想設定一個使用者命名的規則,讓使用者名稱包含字元,數字,下劃線和連字元,以及限制字元的個數,好讓名字看起來沒那麼醜.我們使用以下正規表示式來驗證一個使用者名稱: 以上的正規表示式可以接受john_doe,john12_as.但不匹配Jo,因為它包含了大寫的字母而且太短了. 本文將以C++語言為例,介紹其中的正規表示式相關知識。

C++中正規表示式的API基本上都位於標頭檔案中。

部分程式碼為了簡化書寫,都已經預設做了以下操作: #include #include usingnamespacestd; 入門示例 為了使大家有一個直觀的感受,文章的開頭先通過一些入門示例給大家一個直觀的感受。

在這個基礎之上,再詳細講解其中的細節。

使用正規表示式的大致流程如下:首先你有一段需要處理的文字。

這可能是一個字串物件,也可能是一個文字檔案,或者是一大堆日誌。

接下來你會有特定的目標,例如:找出文字中所有的時間和日期。

這個時候你就需要根據可能的格式寫出具體的正規表示式,例如,日期的格式是:2020-01-01,那麼你的正規表示式可能是這樣:\d{4}-\d{2}-\d{2}。

(你現在不必糾結與這個正規表示式是什麼意思,因為這是本文接下來要講解的內容。

) 有了正規表示式之後,你需要將你的文字和正規表示式交給正規表示式引擎–由C++語言(或者其他語言)提供。

引擎會在文字中搜尋到匹配的結果。

這個結果的格式可能是包含了多個組,例如:你可能需要分離出年份和月份。

有了引擎返回的結果之後,你就可以進一步處理了。

使用正規表示式的流程大體都是一致的,下面是最常見(其他形式大多為其變種)的三種使用方式。

匹配 匹配是判斷給定的字串是否符合某個正規表示式。

例如:你想判斷當前文字是否全部由數字構成。

下面是一段程式碼示例: strings1="ab123cdef";//① strings2="123456789";//② regexex("\\d+");//③ cout< #include usingnamespacestd; staticvoidsearch_string(conststring&str,constregex&reg_ex){//① for(string::size_typei=0;i #include usingnamespacestd; staticvoidsearch_by_regex(constchar*regex_s, conststring&s){//① regexreg_ex(regex_s); smatchmatch_result;//② cout.width(14);//③ if(regex_search(s,match_result,reg_ex)){//④ cout< wcregex_iterator regex_iterator sregex_iterator regex_iteratorstd::string::const_iterator wsregex_iterator regex_iteratorstd::wstring::const_iterator 在一大段文字中查詢所有匹配的目標,這是一個非常常見的需求。

而迭代器正好滿足這一需求,它會依次返回它從文字中找到的匹配內容。

示例:統計出文字中一共出現了多個單詞。

思路:組成單詞的字母可以使用[[:alpha:]]字元類來表達,一個單詞至少有一個字母,因此這個正規表示式可以寫成:[[:alpha:]]+。

然後藉助迭代器便可以統計出總數量。

程式碼示例如下: #include #include #include usingnamespacestd; intmain(){ regexword_regex("[[:alpha:]]+");//① ifstreamfile("./content.txt");//② stringline; intword_count=0; while(getline(file,line)){//③ autoiter_begin=sregex_iterator(line.begin(), line.end(), word_regex);//④ autoiter_end=sregex_iterator();//⑤ for(autoiter=iter_begin;iter!=iter_end;iter++){//⑥ word_count++;//⑦ //cout<str()< 在建立正規表示式物件的時候,除了描述規則本身的字串之外,還可以傳遞一個flag_type型別的引數,該引數的值定義在std::regex_constants::syntax_option_type中。

它們中與“文法”相關的已經在上文介紹過了。

剩下的還有幾個說明如下: 值 效果 icase 以不考慮大小寫進行字元匹配。

nosubs 進行匹配時,將所有被標記的子表示式exprexpr當做非標記的子表示式?:expr?:expr。

不將匹配儲存於提供的std::regex_match結構中,且mark_count()為零 optimize 指示正規表示式引擎進行更快的匹配,帶有令構造變慢的潛在開銷。

例如這可能表示將非確定FSA轉換為確定FSA。

collate 形如“[a-b]”的字元範圍將對本地環境敏感。

multiline(C++17) 若選擇ECMAScript引擎,則指定^匹配行首,$應該匹配行尾。

這其中,第一個是我們最常用的。

示例:匹配文字中“regularexpression”所有的單複數,並且不區分大小寫。

思路:單詞的首字母有些會大寫,我們可以通過[Rr]來匹配大寫或者小寫的R字母,但實際上,使用icase無疑會更方便。

程式碼示例: #include #include #include usingnamespacestd; intmain(){ regexword_regex("regularexpressions?",regex::icase); ifstreamfile("./content.txt"); stringline; while(getline(file,line)){ autoiter_begin=sregex_iterator(line.begin(), line.end(), word_regex); autoiter_end=sregex_iterator(); for(autoiter=iter_begin;iter!=iter_end;iter++){ cout<str()< std::wcmatch std::match_results std::smatch std::match_resultsstd::string::const_iterator std::wsmatch std::match_resultsstd::wstring::const_iterator 當我們使用正規表示式時,我們的目標常常不單單是判斷或者查詢完整匹配的內容。

而是需要捕獲匹配結果中的子串。

例如:我們不僅要匹配出日期,還要捕獲日期中的年份,月份等資訊。

這個時候就要使用分組功能。

我們在介紹正規表示式特殊字元的時候,提到過圓括號(和)。

它們的作用就是分組。

當你在正規表示式中配對的使用圓括號時,就會形成一個分組,一個正規表示式中可以包含多個分組。

分組通過編號0,1,2,…來區分。

編號0的分組是匹配的整體,其他編號根據括號的順序來確定。

這些分組最終可以在匹配完成之後,可以通過std::match_results的API來獲取。

這些API如下表所示: API 說明 empty 檢查匹配是否成功 size 返回完成建立的結果狀態中的匹配數 max_size 返回子匹配的最大可能數量 length 返回特定分組的長度 position 分會特定分組首字元的位置 str 返回特定分組的字元序列 operation[] 返回指定的分組 prefix 返回目標序列起始和完整匹配起始之間的分組 suffix 返回完整匹配結果和目標序列結尾之間的分組 在C++中,分組叫做子匹配(sub_match)。

std::sub_match這個型別只有一個預設建構函式,通常你不會主動建立它,而是使用std::match_results的介面來獲取它的物件。

示例:查詢出文字中所有的年代,並分離出世紀的部分和年份的部分。

思路:年代的格式是四位數字加上“s”作為字尾。

我們可以通過分組的形式分離出兩個部分。

圖示如下: 程式碼示例: #include #include #include usingnamespacestd; intmain(){ regexword_regex(R"((\d{2})(\d{2})s)");//① ifstreamfile("./content.txt"); stringline; while(getline(file,line)){ autoiter_begin=sregex_iterator(line.begin(), line.end(), word_regex); autoiter_end=sregex_iterator(); for(autoiter=iter_begin;iter!=iter_end;iter++){ cout<str(0)<size()<str(1)<length(1)<position(1)<position(2)< #include usingnamespacestd; voidfindIn(constchar*content,constchar*reg_ex){ cout< #include usingnamespacestd; voidisMatch(constchar*content,constchar*reg_ex){ cout<



請為這篇文章評分?