熱線(xian)電話:0755-23712116
郵箱:contact@legoupos.cn
地址:深圳市寶安區沙井街(jie)道后亭(ting)茅洲山工業園工業大(da)廈全(quan)至(zhi)科技創新園科創大(da)廈2層(ceng)2A
正(zheng)則(ze)表(biao)達式是一組由(you)字母和符(fu)號組成的(de)特(te)殊文(wen)本, 當(dang)你(ni)想要判斷許多字符(fu)串是否符(fu)合某個(ge)特(te)定格式;當(dang)你(ni)想在一大(da)段文(wen)本中(zhong)查找出所(suo)有的(de)日期和時(shi)間;當(dang)你(ni)想要修改大(da)量日志(zhi)中(zhong)所(suo)有的(de)時(shi)間格式,在這些情況(kuang)下,正(zheng)則(ze)表(biao)達式都能幫(bang)上(shang)忙。
簡單來(lai)說(shuo),正(zheng)則(ze)表(biao)達式描述了一(yi)系(xi)列規(gui)(gui)則(ze),通過這些規(gui)(gui)則(ze),可(ke)以在字符串中(zhong)找(zhao)到(dao)相關的內容,規(gui)(gui)則(ze)使得(de)搜索的能力更(geng)加強大。匹配的過程由正(zheng)則(ze)表(biao)達式引(yin)(yin)擎(qing)完成(cheng)。開發者通常不需要關心(xin)正(zheng)則(ze)表(biao)達式引(yin)(yin)擎(qing)的實(shi)現(xian)細節,直接使用(yong)其(qi)提供(gong)的能力即可(ke)。
大家可以先想(xiang)象你(ni)正在寫一個(ge)應用(yong), 然后(hou)你(ni)想(xiang)設定一個(ge)用(yong)戶(hu)命名的規則(ze), 讓用(yong)戶(hu)名包含字(zi)(zi)符,數(shu)字(zi)(zi),下(xia)劃(hua)線和連字(zi)(zi)符,以及限(xian)制(zhi)字(zi)(zi)符的個(ge)數(shu),好讓名字(zi)(zi)看(kan)起來沒那么丑. 我(wo)們使用(yong)以下(xia)正則(ze)表達式(shi)來驗證一個(ge)用(yong)戶(hu)名:
以上的正則表達式可以接受 john_doe , john12_as . 但不匹配 Jo , 因(yin)為它包含了大寫的字母(mu)而且太短了.
本文將以C++語言為例,介紹其中的正則(ze)表達式(shi)相關知識。
C++中正則表達式的API基本上都位于
部分代碼為了簡化(hua)書寫,都已經默認做(zuo)了以(yi)下操作:
為了使大家有一(yi)(yi)個(ge)直觀(guan)的(de)感(gan)(gan)受(shou),文(wen)章的(de)開頭先通過一(yi)(yi)些入門示例給大家一(yi)(yi)個(ge)直觀(guan)的(de)感(gan)(gan)受(shou)。在(zai)這個(ge)基礎之上,再詳細講解(jie)其中的(de)細節(jie)。
使用正則表達式的大致流程如下:首先你有一段需要處理的文本。這可能是一個字符串對象,也可能是一個文本文件,或者是一大堆日志。接下來你會有特定的目標,例如:找出文本中所有的時間和日期。這個時候你就需要根據可能的格式寫出具體的正則表達式,例如,日期的格式是:2020-01-01,那么你的正則表達式可能是這樣:
。(你(ni)現在(zai)不必糾結與這個正(zheng)則表(biao)達式是什么意思,因為這是本文接下來要講解的內容。)
有了正則表(biao)(biao)達(da)(da)式(shi)之后(hou),你(ni)需要將你(ni)的(de)文本(ben)和正則表(biao)(biao)達(da)(da)式(shi)交給正則表(biao)(biao)達(da)(da)式(shi)引擎(qing) – 由C++語言(或者其(qi)他語言)提供。引擎(qing)會在文本(ben)中搜索到匹配的(de)結果。這個結果的(de)格式(shi)可能是包含了多個組,例如:你(ni)可能需要分離(li)出年份(fen)和月(yue)份(fen)。有了引擎(qing)返(fan)回的(de)結果之后(hou),你(ni)就可以進一(yi)步處理了。
使用(yong)正則表達式的流(liu)程(cheng)大體都是一致的,下(xia)面是最常見(其他形式大多為其變種)的三種使用(yong)方式。
匹配是判斷(duan)給定(ding)的字符串是否(fou)符合某個正(zheng)則表(biao)達式。例如(ru):你想(xiang)判斷(duan)當前文本是否(fou)全(quan)部由數字構(gou)成。
下(xia)面是一段(duan)代碼(ma)示例:
在這段代碼中:

判斷第一個字符串是否匹配,這里將返回false
判斷第二個字符串是否匹配,這里將返回true這段代碼輸出如下:
還有一(yi)些(xie)時候,我們(men)要判(pan)斷的并非是文(wen)本的全體是否匹配。而是在一(yi)大段文(wen)本中搜索匹配的目標。
下面(mian)是一段代碼示例,這段示例演示了在(zai)一個字符串中查找數(shu)字:

來保存匹配的結果。除了
,還有
也很常用。前者是以
的形式返回結果,后者是以
的形式返回結果。
函數搜索結果這段代碼輸出如下:
最后,使(shi)用正則(ze)表達(da)式的還有(you)一個(ge)常(chang)見功能是(shi)文本替換(huan)。很多的編輯(ji)器都有(you)這樣的功能。
例如,下圖是我(wo)的(de)(de)Visual Studio編譯器,在搜索(suo)替(ti)(ti)換文本(ben)的(de)(de)時候,可以使用正則(ze)表(biao)(biao)達(da)式(shi),這(zhe)時搜索(suo)的(de)(de)能力就更加強(qiang)大了(le)。“Find:”部分可以通過正則(ze)表(biao)(biao)達(da)式(shi)來描述待替(ti)(ti)換的(de)(de)字(zi)符串(chuan),“Replace:”部分填寫(xie)替(ti)(ti)換的(de)(de)字(zi)符串(chuan)。
下面(mian)是在C++中(zhong)使用正則(ze)表達式(shi)完(wan)成字符串替換的(de)代碼(ma)示例:

完成替換
輸出結果最終(zhong)輸出的字符串如下:
通過上面的三個示例我們看到,
,
和
三個函數(shu)是正(zheng)則表達式(shi)的核心,它們會運行正(zheng)則表達式(shi)引擎完成匹配,查(cha)找和替(ti)換任(ren)務。
C++中內置(zhi)了(le)多種正(zheng)則表達式(shi)文法,在創建(jian)正(zheng)則表達式(shi)的時候可以通過參數來選擇。
不同的文法在表達上有一些不同,如果你原先已經很熟悉
或者
文法的正則表達式,你可以直接使用它們。對于其他人來說,我們直接使用默認的ECMAScript文法即可(
的正則表達式也是使用ECMAScript文法)。
C++ 中的 ECMAScript 正則表達式文法是 ,你可以點擊鏈(lian)接查看詳細內容。
下文中,將會 引用 :關于的解釋。
在代碼(ma)中寫字符串(chuan)有(you)時(shi)候是比較麻煩的,因為很多字符需要(yao)通過反斜(xie)杠(gang)轉義(yi)。當有(you)多個反斜(xie)杠(gang)連在一起時(shi),就(jiu)很容易寫錯(cuo)或者理解錯(cuo)了(le)。
當通過字符串來寫正則表達式時,這個問題就更嚴重了。因為正則表達式本身也有一些字符需要轉義。例如,對于這樣一個字符串
大部分人(ren)恐怕很難一(yi)眼看出(chu)其含義了。
在正則表達式很復雜的時候,推薦大家使用來表達。這種表達式是告訴編譯器:這里的內容是純字符串,因此不再需要增加反斜杠來轉(zhuan)義特殊字符。
Raw string literal 的格式如下:
這其中:
也就是說,
中的
是你(ni)需要的字符串本身(shen)。
下(xia)面是一個代(dai)碼示(shi)例:
它將輸出:
可以看到(dao),這里的雙引號和反(fan)斜杠不會被解(jie)(jie)釋成轉(zhuan)義字符,而是當成字符串內容本身,因此會原樣(yang)輸出。這樣(yang)就減少(shao)了轉(zhuan)義字符的復雜度,于是更容易理(li)解(jie)(jie)了。
正則表(biao)達式(shi)本身(shen)定義(yi)了一(yi)些特(te)殊(shu)的字符(fu),這些字符(fu)有著特(te)殊(shu)的含義(yi)。它們如下表(biao)所示。
這些(xie)字符并不少(shao),剛開始接觸(chu)可能記不住(zhu),但(dan)隨(sui)著下文的(de)講解,相(xiang)信(xin)你會逐漸熟悉它們(men)。
字(zi)符(fu)類,顧名(ming)思義:是對字(zi)符(fu)的分類。
例如:1234567890這些都(dou)屬于數字字符類。除(chu)此之外(wai),還有其他的分類,它們如下表所示(shi):
這里我們可以看到:

作為標識,因此這兩個字符是正則表達式的中的特殊字符。如果是想使用這兩個字符本身,需要對它們進行轉義。
內部,通過
來描述字符類的名稱。
中可以通過
表示否定,即:字符類的反面。接下(xia)來我(wo)們看一個(ge)代(dai)碼示(shi)例:
這段代碼稍(shao)微有些長,但還是比較好理解的。
該程序的輸出如下:
請仔細看一下這個輸出(chu),并確(que)認與你的(de)(de)認知(zhi)是(shi)否(fou)一致。這里的(de)(de)有(you)些字(zi)符(fu)(fu)類包含(han)了(le)換行符(fu)(fu),因此在輸出(chu)的(de)(de)結果(guo)中(zhong)也是(shi)換行的(de)(de)。
上面的(de)示例中,我們(men)一次只(zhi)匹配了一個字符。這(zhe)樣(yang)做效率(lv)是(shi)很(hen)低的(de)。
在很(hen)多(duo)時候,我(wo)們(men)當然是想一(yi)次性匹配出一(yi)個(ge)完(wan)整的字符(fu)(fu)串。例(li)如(ru):一(yi)個(ge)手機號碼。這種情況(kuang)下,其實是多(duo)個(ge)數字字符(fu)(fu)的重復。
下面(mian)就是在正則(ze)表達式中描述(shu)重(zhong)復的(de)(de)方式。它們通常(chang)跟(gen)在字符(fu)類的(de)(de)后面(mian),描述(shu)該字符(fu)出(chu)現多次。
知道重復(fu)的方法之后,正(zheng)則表達式的查(cha)找(zhao)能(neng)力就更強大了。看一下下面這個代(dai)碼示例:
在這段代碼中:
match_result
用來存儲查找的結果。regex_search
在字符串中查找匹配字符。[[:alnum:]]{5}
是指:字符或者數字出現5次。\\w{5,}
是指:字母,數字或者下劃線出現5次或更多次。R"(\W{3,5})"
是指:非字母,數字或者下劃線出現3次到5次。[[:digit:]]*
是指:數字出現任意多次。.+
是指:任意字符出現至少1次。[[:lower:]]?
是指:小寫字母出現0次或者1次。該程序輸出如下: