上個(gè)公司的項(xiàng)目是個(gè)視頻直播即時(shí)聊天的APP,聊天內(nèi)容有文字饥伊,并且文字分好幾個(gè)部分例如“某某人對某某人說:blabla......”這就已經(jīng)三個(gè)部分了(某某人象浑,某某人,說的內(nèi)容)琅豆,每個(gè)部分按照需求文字的顏色還要不一樣愉豺;除此之外,還有表情茫因,當(dāng)然服務(wù)端發(fā)過來的都是帶有標(biāo)識的文字蚪拦,比如一個(gè)微笑表情,服務(wù)端過來的是這樣的:[微笑]冻押,你沒有看錯(cuò)驰贷,是漢字,哎洛巢!不說了括袒。當(dāng)時(shí)作的時(shí)候用的正則表達(dá)式去摳字符串,現(xiàn)在記一下吧稿茉,我這人腦子里存不了東西锹锰。
??正則表達(dá)式我的理解就像央視的一個(gè)節(jié)目《墻來了》,被匹配的字符串就是那些搞怪的參賽者漓库,正則表達(dá)式就是墻上面的形狀輪廓恃慧,匹配的過程就是人擺出的形狀和墻上的輪廓是否契合。
精確匹配和字符轉(zhuǎn)義
就是匹配字符或字符串本身渺蒿,例如Hello痢士,就是要匹配Hello(好傻的表達(dá),知道這個(gè)意思就行)茂装。不過一些字符在正則表達(dá)式里有特別的含義怠蹂,匹配這些字符本身,就需要借助“\”轉(zhuǎn)義為普通字符少态,比如.
在正則表達(dá)式中表示除換行符外的任意字符城侧。那要匹配.
本身,就這樣了“\.”况增,That's it赞庶。
元字符
不廢話,看表格最清楚了:
元字符 | 匹配內(nèi)容 |
---|---|
. | 匹配除換行符以外的任意字符 |
\w | 匹配字母或數(shù)字或下劃線或漢字 |
\s | 匹配任意的空白字符(空格、制表符歧强、換頁符澜薄、換行符、回車符等) |
\d | 匹配任意數(shù)字 |
\b | 匹配單詞的開始或結(jié)束位置 |
^ | 匹配行或字符串開始位置摊册、在字符類中取反 |
$ | 匹配行或字符串結(jié)束位置 |
重復(fù)匹配
現(xiàn)在假如匹配5個(gè)a肤京,這么寫aaaaa
有點(diǎn)不那么講究,這么寫a{5}
就舒服多了茅特。當(dāng)然在重復(fù)匹配里也有像元字符一類表示特定重復(fù)匹配次數(shù)的字符忘分,看表就明白了:
重復(fù)匹配規(guī)則 | 說明 |
---|---|
* | 重復(fù)匹配零次或更多次 |
+ | 重復(fù)匹配一次或更多次 |
? | 重復(fù)匹配零次或者一次 |
{n} | 重復(fù)匹配n次 |
{n,} | 重復(fù)匹配n次或更多次 |
{n,m} | 重復(fù)匹配n到m次 |
字符類
可以看出元字符定義了一個(gè)匹配范圍(字符或者位置)。通過字符類我們也可以定義一個(gè)匹配范圍白修,很簡單妒峦,快使用[]
。比如我們現(xiàn)在匹配abcd這個(gè)范圍的字符串就可以這樣寫[abcd]
兵睛。ok肯骇,那么現(xiàn)在定義大寫英文字母這個(gè)匹配范圍,該如何是好祖很?[A-Z]
笛丙,That't it!不用解釋那個(gè)迷人的-
假颇,你該知道ta的用處了胚鸯。來個(gè)例子定義js變量命名規(guī)范的正則
:^[a-zA-Z\_\$][a-zA-Z0-9\_\$]*
。
取反
還記得那個(gè)^
嗎笨鸡?ta在字符類中還有別的含義姜钳,看個(gè)例子[^a-z]
表示除了小寫英文字母外其它的字符,在字符類中^
還表示取這個(gè)字符類相反的匹配范圍镜豹。字符類可以這樣取反傲须,元字符也有相對應(yīng)的元字符用于對該元字符取反(好厲害的表達(dá)水準(zhǔn))蓝牲,而且這樣的元字符是非常有規(guī)律的趟脂,看表找一下唄:
取反元字符 | 匹配說明 |
---|---|
\W | 匹配任意不是字母,數(shù)字例衍,下劃線昔期,漢字的字符 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非數(shù)字的字符 |
\B | 匹配不是單詞開始或結(jié)束的位置 |
分支條件
這個(gè)名字也是看其他人的,不過管他呢》鹦現(xiàn)在有這樣一個(gè)需求:有a,b兩個(gè)匹配范圍硼一,通過組合就會(huì)有4種匹配范圍了(a,b梦抢,ab般贼,ba),如果一個(gè)字符串滿足這4種的任一種都算匹配成功。怎么搞哼蛆?快使用|
蕊梧,這么寫:a|b|ab|ba
。That's it蚌讼!
分組及后向引用
看到現(xiàn)在你大概也感覺到不管是元字符庞瘸,還是字符類塞琼,ta們(-:瞧瞧這中西合璧的語言風(fēng)格:-)都定義了一個(gè)字符匹配的范圍,別的情況還好甘改,但是當(dāng)重復(fù)匹配一組字符的時(shí)候就有困難了。例如重復(fù)匹配abc三次灭抑,不好弄了吧十艾,還是快使用()
吧,(abc){3}
腾节。就是這么簡單疟羹,就是這么酸爽。
??上面只是()
的一個(gè)非常小的用法禀倔。下面看大招榄融,一個(gè)()
就是一個(gè)組(匹配小括號字符除外啊)救湖,并分配有組號愧杯。默認(rèn)情況下,從左向右鞋既,以(
為標(biāo)記力九,第一個(gè)(
組號為1,然后依次類推邑闺。這個(gè)組號有啥用跌前,可以引用成功匹配組號對應(yīng)組定義的規(guī)則的字符串內(nèi)容,注意加重的文字陡舅,不是引用組號對應(yīng)組的匹配規(guī)則抵乓,而是成功匹配這個(gè)規(guī)則的字符串本身。怎么引用呢靶衍,使用\組號
灾炭。
??別廢話,說例子吧颅眶!
??\b([a-zA-Z]+)\b\s+\1\b
蜈出,這個(gè)正則分三部分:\b([a-zA-Z]+)\b
、\s
涛酗、\1\b
≌≡現(xiàn)在有Mookaka
匹配第一部分偷厦,然后一個(gè)空白符Mookaka
,之后\1
就引用第一部分那個(gè)分組匹配成功的字符串也就是Mookaka
燕刻,所以整個(gè)正則可以匹配像Mookaka Mookaka
這樣的字符串沪哺。
??當(dāng)然像1,2這樣的組號看不出所表達(dá)的意義酌儒,我們也可以自己指定組號辜妓,像這樣(?<你的組號>匹配規(guī)則)
或者(?\
你的組號`匹配規(guī)則)。當(dāng)然有時(shí)你不需要什么這個(gè)分組啊忌怎,引用什么的籍滴,就只是想單純的重復(fù)匹配一組字符串,可以這樣寫**
(?:匹配規(guī)則)`**榴啸,這樣只匹配規(guī)則孽惰,不分配組號,也不捕獲成功匹配的字符串內(nèi)容鸥印。
零寬斷言
不糾結(jié)這個(gè)名字勋功,知道這個(gè)名詞指的是什么就行。先舉一個(gè)例子库说,大家都知道QQ郵箱的格式一般前面是10位數(shù)字狂鞋,然后是@qq.com
,現(xiàn)在我們有一批郵箱地址潜的,想從這些地址中摳出qq號骚揍,我們只要qq號,后面什么@qq.com
就不要了啰挪,于是你寫了一個(gè)真正\d{10,11}@qq\.com
信不,之后你獲得的是完整的郵箱地址,接下來你會(huì)在構(gòu)建一個(gè)正則什么的來取這個(gè)地址字符串前面的qq號亡呵。能不能定義這樣一種正則抽活,要取的字符串本身匹配定義的正則,并且以這個(gè)字符串為基點(diǎn)ta的前面或后面也匹配定義的其它正則锰什,零寬斷言就是干這事的下硕。例如上面的例子,構(gòu)建正則\d{10,11}(?=@qq\.com)
歇由,那么這個(gè)正則就直接取前面的qq號卵牍。
??零寬斷言就是定義要獲取的匹配正則的字符串位置的前面或后面需要符合的規(guī)則果港,但符合這個(gè)規(guī)則的字符串不在取出字符串之列沦泌,看表格(這里把那個(gè)要獲取的字符串稱為基點(diǎn)字符串吧):
表達(dá)式 | 說明 |
---|---|
(?=RegExp) | 基點(diǎn)字符串后跟符合RegExp定義的內(nèi)容 |
(?<=RegExp) | 基點(diǎn)字符串前面跟符合REgExp定義的內(nèi)容 |
(?!RegExp) | 基點(diǎn)字符串后面不跟符合RegExp定義的內(nèi)容 |
(?<!RegExp) | 基點(diǎn)字符串前面不跟符合RegExp定義的內(nèi)容 |
貪婪、懶惰匹配
一般情況下辛掠,正則表達(dá)式里含有重復(fù)谢谦,那么在使整個(gè)正則表達(dá)式能夠匹配的前提下释牺,重復(fù)將會(huì)匹配盡可能多的字符』赝欤看這樣一個(gè)正則^(\d+)(0*)$
没咙,注意這里有兩個(gè)分組,如果102300和ta匹配千劈,第一個(gè)組獲取102300
祭刚,第二個(gè)組什么也捕獲不了,但實(shí)際上我們希望組一獲取1023
墙牌,組二捕獲剩下的零的涡驮。為了不讓正則在有重復(fù)匹配時(shí)太過貪心,在可能發(fā)生貪婪匹配的后面加個(gè)?
喜滨,That's is捉捅。看表格:
懶惰匹配 | 說明 |
---|---|
*? | 重復(fù)匹配任意次虽风,但盡可能少重復(fù) |
+? | 重復(fù)1次或更多次棒口,但盡可能少重復(fù) |
?? | 重復(fù)0次或1次,但盡可能少重復(fù) |
{n,m}? | 重復(fù)n次到m次辜膝,但盡可能少重復(fù) |
{n,}? | 重復(fù)n次以上无牵,但盡可能少重復(fù) |
注釋
還可以給正則加注釋,開發(fā)APP的時(shí)候用了很多正則表達(dá)式厂抖,有的還很長有點(diǎn)復(fù)雜合敦,開發(fā)組老大看著頭暈,提示正則可以加注釋验游。但是實(shí)際上也沒好多上充岛,反而正則更長看著更難受。用(?#你的注釋)
的方式來加注釋耕蝉,看個(gè)例子:2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)
崔梗。
平衡組
假如現(xiàn)在我要從一個(gè)字符串中提取數(shù)學(xué)表達(dá)式,那么提取的字符串中如果有括號垒在,左括號和右括號的數(shù)量是一樣的蒜魄。先看一下下面的規(guī)則:
- (?'group'RegExp) 把匹配RegExp規(guī)則的內(nèi)容命名為 group,并壓入棧中场躯。
- (?'-group'RegExp) 假如匹配RegEXp規(guī)則谈为,把最后壓入棧且名為group的捕獲內(nèi)容彈出,如果棧是空的踢关,則這個(gè)分組的匹配失敗伞鲫。
- (?(group)RegExp1|RegExp2) 假如棧上有名為group的捕獲內(nèi)容,就接著匹配RegExp1表達(dá)式签舞,否則繼續(xù)匹配RegExp2表達(dá)式秕脓。
- (?!) 總是匹配失敗柒瓣。
??總是匹配失敗,搞什么吠架?
??匹配失敗時(shí)芙贫,正則表達(dá)式引擎會(huì)進(jìn)行回溯也就是放棄最前面或最后面的已經(jīng)捕獲了的字符,使整個(gè)表達(dá)式得到匹配傍药。
??這樣用(?'bracket' \()
磺平,遇到左括號就在棧里面記一下,遇到右括號拐辽,就用(?'-bracket'\))
褪秀,把對應(yīng)的左括號在棧中的記錄去掉;如果左括號比右括號多那么最后棧中一定還有記錄薛训,那么用(?(bracket)(?!))
故意匹配失敗媒吗,讓正則表達(dá)式引擎去掉結(jié)果字符串中在棧里有記錄的字符串。這樣左右括號的數(shù)量就平衡了乙埃。