介紹
在實(shí)際項(xiàng)目中有個(gè)功能的實(shí)現(xiàn)需要解析一些特定模式的字符串。而在已有的代碼庫(kù)中,在已實(shí)現(xiàn)的部分功能中,都是使用檢測(cè)特定的字符,使用這種方法的缺點(diǎn)是:
- 邏輯上很容易出錯(cuò)
- 很容易漏掉對(duì)一些邊界條件的檢查
- 代碼復(fù)雜難以理解、維護(hù)
- 性能差
看到代碼庫(kù)中有一個(gè)cpp,整個(gè)cpp兩千多行代碼,有個(gè)方法里,光解析字符串的就有400余行!一個(gè)個(gè)字符對(duì)比過(guò)去,真是不堪入目。而且上面很多注釋都已經(jīng)過(guò)期,很多代碼的書(shū)寫(xiě)風(fēng)格也各不相同,基本可以判斷是過(guò)了很多人手的。
在這種情況下,基本沒(méi)辦法還沿著這條老路走下去,自然而然就想到了使用正則表達(dá)式。而我自己在正則表達(dá)式方面沒(méi)有實(shí)際應(yīng)用的經(jīng)驗(yàn),尤其是對(duì)于書(shū)寫(xiě)匹配規(guī)則也是一知半解。第一時(shí)間就想到從網(wǎng)上找點(diǎn)資料,先大致了解下。但是度娘的結(jié)果依舊還是讓人很失望。(當(dāng)然,如果是想要查找一些比較專業(yè)的知識(shí),度娘的結(jié)果每次都會(huì)讓人心碎,無(wú)不都是千篇一律的拷貝。但是通常度娘生活方面的還是可以)后來(lái)就放棄度娘的查詢結(jié)果,F(xiàn)Q到了外面去找,也找到了一些比較基礎(chǔ)的視頻(需FQ)。
這篇文章可以說(shuō)是一個(gè)總結(jié),把在書(shū)寫(xiě)正則表達(dá)式的匹配字符串方面的基礎(chǔ)知識(shí)介紹一下。主要分為以下兩個(gè)個(gè)部分:
- 匹配字符串的基本規(guī)則
- 正則匹配、查找與替代
本文介紹的正則表達(dá)式規(guī)則是ECMAScript。使用的編程語(yǔ)言是C++。其他方面的不做介紹。
匹配字符串的基本規(guī)則
1. 匹配固定的字符串
regex e("abc");
2. 匹配固定字符串,不區(qū)分大小寫(xiě)
regex e("abc", regex_constants::icase);
3. 匹配固定字符串之外多一個(gè)字符,不區(qū)分大小寫(xiě)
regex e("abc.", regex_constants::icase); // . Any character except newline. 1個(gè)字符
4. 匹配0個(gè)或1個(gè)字符
regex e("abc?"); // ? Zero or 1 preceding character. 匹配?前一個(gè)字符
5. 匹配0個(gè)或多個(gè)字符
regex e("abc*"); // * Zero or more preceding character. 匹配*前一個(gè)字符
6. 匹配1個(gè)或多個(gè)字符
regex e("abc+"); // + One or more preceding character. 匹配+前一個(gè)字符
7. 匹配特定字符串中的字符
regex e("ab[cd]*"); // [...] Any character inside square brackets. 匹配[]內(nèi)的任意字符
8. 匹配非特定字符串的字符
regex e("ab[^cd]*"); // [...] Any character not inside square brackets. 匹配非[]內(nèi)的任意字符
9. 匹配特定字符串,且指定數(shù)量
regex e("ab[cd]{3}"); // {n} 匹配{}之前任意字符,且字符個(gè)數(shù)為3個(gè)
10. 匹配特定字符串,指定數(shù)量范圍
regex e("ab[cd]{3,}"); // {n} 匹配{}之前任意字符,且字符個(gè)數(shù)為3個(gè)或3個(gè)以上
regex e("ab[cd]{3,5}"); // {n} 匹配{}之前任意字符,且字符個(gè)數(shù)為3個(gè)以上,5個(gè)以下閉區(qū)間
11. 匹配規(guī)則中的某一個(gè)規(guī)則
regex e("abc|de[fg]"); // | 匹配|兩邊的任意一個(gè)規(guī)則
12. 匹配分組
regex e("(abc)de+"); // () ()表示一個(gè)子分組
13. 匹配子分組
regex e("(abc)de+\\1"); // () ()表示一個(gè)子分組,而\1表示在此位置匹配第一個(gè)分組的內(nèi)容
regex e("(abc)c(de+)\\2\\1"); // \2 表示的是在此匹配第二個(gè)分組的內(nèi)容
14. 匹配某個(gè)字符串開(kāi)頭
regex e("^abc.");
// ^ begin of the string 查找以abc開(kāi)頭的子字符串
15. 匹配某個(gè)字符串結(jié)尾
regex e("abc.$");
// $ end of the string 查找以abc結(jié)尾的子字符串
以上是最基本的匹配模式的書(shū)寫(xiě)。通常如果要匹配特定的字符,需要使用\進(jìn)行轉(zhuǎn)義,比如在匹配字符串中需要匹配".",那么在匹配字符串中應(yīng)該在特定字符前加上\。出了以上的基本規(guī)則,如果還不滿足特定的需要,那么可以參考此鏈接。使用了解基本的匹配模式后,需要使用正則表達(dá)式進(jìn)行匹配、查找或者替代。
正則匹配、查找與替代
書(shū)寫(xiě)好模式字符串后,需要將待匹配的字符串和模式字符串進(jìn)行一定規(guī)則的匹配。包括三種方式:匹配(regex_match)、查找(regex_search)、替換(regex_replace)。
匹配很簡(jiǎn)單,直接將待匹配字符串和模式字符串傳入到regex_match中,返回一個(gè)bool量來(lái)指明待匹配的字符串是否滿足模式字符串的規(guī)則。匹配整個(gè)str字符串。
bool match = regex_match(str, e);
// 匹配整個(gè)字符串str
查找是在整個(gè)字符串中找到和滿足模式字符串的子字符串。也就是只要str中存在滿足模式字符串就會(huì)返回true。
bool match = regex_search(str, e);
// 查找字符串str中匹配e規(guī)則的子字符串
但是很多情況下,光是返回一個(gè)是否匹配的bool量是不夠的,我們需要拿到匹配的子字符串。那么就需要在模式字符串中將匹配字符串分組,參考【匹配字符串的基本規(guī)則】第12點(diǎn)。再將smatch傳入到regex_search中,就可以獲得滿足每個(gè)子分組的字符串。
smatch m;
bool found = regex_search(str, m, e);
for (int n = 0; n m.size(); ++n)
{
cout "m[" n "].str()=" m[n].str() endl;
}
替換也是基于模式字符串在分組情況下完成的。
cout regex_replace(str, e, "$1 is on $2");
此時(shí),會(huì)在滿足分組1和分組2的字符串中間加上“ is on”。
以上三個(gè)函數(shù)有很多版本的重載,可以滿足不同情況下的需求。
實(shí)戰(zhàn)
要求:找出滿足sectionA("sectionB")或者sectionA ("sectionB")的模式字符串。且分離出sectionA、sectionB。sectionA和sectionB不會(huì)出現(xiàn)數(shù)字,字符可大小寫(xiě),至少有一個(gè)字符。
分析:根據(jù)要求,大致可分為兩個(gè)部分,也就是sectionA和sectionaB。這是就需要用到分組。
第一步:寫(xiě)出滿足section情況的模式字符串
[a-zA-Z]+
第二步:在sectionA和sectionB中可能會(huì)出現(xiàn)空格。暫且假設(shè)至多有1個(gè)空格
\\s?
將以上兩個(gè)情況組合起來(lái),也就是能滿足我們需求的模式字符串。但是如何組織才能讓其分為兩組呢?
[a-zA-Z]+\\s[a-zA-Z]+
上面這種寫(xiě)法肯定不對(duì)的,根據(jù)分組規(guī)則,需要將分組以()進(jìn)行區(qū)分
regex e("([a-zA-Z]+)\\s?\\(\"([a-zA-Z]+)\"\\)");
此時(shí),在\\s?后面的\\(\"是為了滿足sectionB外層的引號(hào)和括號(hào)進(jìn)行的轉(zhuǎn)義。
以上完成后,可先用regex_match進(jìn)行匹配,如果匹配,那么繼續(xù)使用regex_search對(duì)字符串進(jìn)行查找
if (regex_match(str, e))
{
smatch m;
auto found = regex_search(str, m, e);
for (int n = 0; n m.size(); ++n)
{
cout "m[" n "].str()=" m[n].str() endl;
}
}
else
{
cout "Not matched" endl;
}
對(duì)象m數(shù)組的第一個(gè)字符串是滿足需求的整個(gè)子串,接下來(lái)才是滿足分組1、分組2的子串。
總結(jié)
以上所述是小編給大家介紹的正則表達(dá)式模式匹配字符串基礎(chǔ)知識(shí),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
您可能感興趣的文章:- 正則表達(dá)式匹配不包含某些字符串的技巧
- js 正則表達(dá)式學(xué)習(xí)筆記之匹配字符串
- 正則匹配密碼只能是數(shù)字和字母組合字符串功能【php與js實(shí)現(xiàn)】
- 請(qǐng)教一個(gè)正則表達(dá)式,匹配所有Html標(biāo)簽外部的指定字符串
- 使用正則表達(dá)式匹配[***]樣式的字符串
- 如何使用正則匹配最后一個(gè)字符串詳解