正則表達式入門

前言

倆件事促使我寫這篇文章。一則之前面試面試到了正則,發(fā)現(xiàn)不甚熟悉。二則這些天看jQuery源碼,一些正則看的有點費勁。

準備

先說些題外話。什么是正則表達式?其實正則表達式也叫規(guī)則表達式。個人感覺后者比較貼切。也很納悶Regular Expression為什么會翻譯成正則表達式。知道的朋友可以告知下。
其實這個正則就是字符串匹配工具,它描述了字符串的規(guī)則。無論是初學者還是老司機相信寫起來都費勁,因為是火星文啊有木有。那為什么要學習這個火星文呢?那自然是好處大大啊。
舉個栗子。前倆天解單時有個情況是需要對location.hash解析出#后面的第一個字符串(不包括/)。譬如

//"#/notebooks/17855961"解析出來的得是notebooks
// “#notebooks/17855961”解析出來的得是notebooks
function parseHash(str) {
    var hashArr = str.split('/');
    var res;
    if (hashArr[0] === '#') {
        res = hashArr[1];
    } else {
        res = hashArr[0].substring(1);
    }
    return res;
}
function parseHash(str) {
    var reg = /(?<=^(?:#\/|#))[^\/]+?(?=\/)/;
    return str.match(reg)[0];
}

其實,不用正則也是可以的,當然你得像上面一樣寫一大串代碼。

基礎

元字符

其實就是正則里具有特殊含義的字符。就比如\d代表數(shù)字。
常用元字符

代碼 說明
. 匹配除換行符以外的任意字符
\w 匹配字母或數(shù)字或下劃線
\s 匹配任意的空白符
\d 匹配數(shù)字
\b 匹配單詞的開始或結(jié)束
^ 匹配字符串的開始(值得注意的是,它在[]里面指的是非,在外面指的是字符串開始,還可以用在零寬斷言)
$ 匹配字符串的結(jié)束

反義詞

常用反義詞
可以看得出好些就是元字符大寫就是其對應的負面。每一對可匹配全部。譬如\w\W

代碼/語法 說明
\W 匹配任意不是字母,數(shù)字,下劃線,漢字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非數(shù)字的字符
\B 匹配不是單詞開頭或結(jié)束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou這幾個字母以外的任意字符

限定符

什么是限定符呢?舉個栗子吧。街上很多人。這個呢可以是元字符,而這個許多就是限定符。和元字符或者表達式模式結(jié)合使用
常用限定符

代碼/語法 說明
* 重復零次或更多次(相當于{0,})
+ 重復一次或更多次(相當于{1,})
? 重復零次或一次(相當于{0,1})
{n} 重復n次
{n,} 重復n次或更多次
{n,m} 重復n到m次

轉(zhuǎn)義

如果有時候你要匹配譬如.、*時會發(fā)現(xiàn)不能匹配,這是因為它們在正則里有其特殊含義(元字符等)。此時就需要轉(zhuǎn)義。即.和*。
eg. https:\\baidu.com就是https:\baidu.com(瞎寫o(╯□╰)o)

類與組以及分支

比如\d匹配數(shù)字,已經(jīng)圈死為數(shù)字類。但是比如現(xiàn)在我想匹配自定義的類別,比如我想看看有沒有1、2、3之中任何字符那就是[123]。比如[0-9]其實和/d一樣。[]就是類,但是可以發(fā)現(xiàn)它只是單個字符,所以也就是字符類。
但是現(xiàn)在我想匹配多字符,那就是組了。比如我要匹配yellow、green、red。(yellow|green|red)。這()就是組,后面接限定符可以重復這個組,用法和元字符類似。|就是分支,也就是或的意思。
這里可能有點亂。給個小栗子總結(jié)下:
怎么匹配國內(nèi)的手機號呢?咋們先想想手機號的規(guī)則。

  1. 手機號一共11位數(shù)字
  2. 前兩位只能是13、14、15、18
  3. 有座機的朋友應該知道打外省的手機號需要加撥0(至少我小時候是這樣子的_
    自然而然就得出答案:0?(13|14|15|18)[0-9]{9}
    自此,差不多可以應付大多數(shù)工作上簡單的情況(工作上真心用得少,以為你會發(fā)現(xiàn)你用的復雜還怕別人看的痛苦,注釋都不好寫( ˇ?ˇ )。更郁悶的是過幾天自己都看不懂)

進階

現(xiàn)在開始講些難些的,用于應付閱讀源碼。

反向引用、捕獲組/非捕獲組

先舉個小例子。比如給定一個字符串,我想先匹配一下一個不定的單詞,然后此單詞之后得跟著相同的單詞。可能有點繞。就是比如前面匹配到了pz,那么緊跟著也得是pz,即pz pz。如果匹配到的時ap,那么緊跟著的也得是ap,即ap ap。
這時候就需要反向引用了。先寫前面的匹配,即\b(\w+)\b\s+,之后怎么寫呢?很簡單:\b(\w+)\b\s+\1\b。這里的\1就是對前面的那個組的引用。
為什么時\1呢?其實每個組都是會分配到一個組號。整個正則表達式匹配到的為分組0,然后從左往右掃,依次分組1、2遞增。注意,順序看(,不要被數(shù)學里的表達式優(yōu)先級給帶入坑。比如:(1(2)(3)),順序如此1、2、3,并非是2、3、1這個順序
有個情況需要注意的是,正則不是某個語言獨有的,所以不同語言的支持情況可能有差異。
PS: JS是不支持給組自定義分配組號的,C#就可以。有興趣的可以了解了解。對了,若是有自定義組號,分配組號時會掃描倆遍。第一遍是給未自定義組號的組分配組號,第二遍給自定義的組分配組號。
如果組過多的話我不想某些組被捕獲,那么可以使用?:。即捕獲組為(exp),非捕獲組為(?:exp)。非捕獲組是不會被分配組號的。也不被捕獲文本。(字符串match返回值不包括非捕獲組)

代碼/語法 說明
(exp) 捕獲組:匹配exp,會被分配組號的,被捕獲文本
(?:(exp) 非捕獲組:匹配exp,不會被分配組號的,也不被捕獲文本

有圖有真相時間(給本小節(jié)所說證明一下)


捕獲組

非捕獲組

零寬斷言(zero-width assertion)

先行斷言、先行否定斷言(JS支持)


好吧,這就是我第一次知道這貨的表情。什么鬼?已經(jīng)很難明白了,現(xiàn)在連命名都這樣子?怎么活。好吧,不急,其實這貨意義就是指定位置應該滿足指定的條件。還是很無語?


  1. 比如匹配小數(shù)的整數(shù)部分,即:/\d+(?=.)/。
    (?=exp)就是正預測先行斷言,也叫先行斷言,只匹配exp前面的位置,斷言自身位置后面跟著exp

    可以看見的是先行斷言是不會被匹配到的,這就是零寬。它只是告訴你是否匹配成功,它不消費任何字符。
  2. 除了先行斷言,還有先行否定斷言,也就是負預測先行斷言。這貨是先行斷言的否定,看名字就看得出來。
    比如匹配后面沒有小數(shù)點的數(shù)字,即:/\d+(?!.)/g
    (?!exp)就是負預測先行斷言,也叫先行否定斷言,只匹配后面沒有exp的位置,斷言自身后面沒有exp

后行斷言、后行否定斷言(目前不支持,但將支持)

其實也不能說不支持,至少此時我試了下我的Chrome(版本 62.0.3202.94)是支持的,不過Firefox是不支持的。

  1. 比如要匹配小數(shù)的小數(shù)部分,即/\d+(?<=.)/
    (?<=exp)就是后行斷言,也叫正回顧后發(fā)斷言,只匹配前面有exp的位置,斷言自身前面有exp
  2. 比如匹配前面沒有小數(shù)點的數(shù)字,即:/(?<!exp)\d+/
    (?<!exp)就是后行否定斷言,也叫負回顧后發(fā)斷言,只匹配前面沒有exp的位置,斷言自身前面沒有exp

正則的性情(貪婪模式、懶惰模式)

正則默認情況下是貪婪的。就比如爬過小說的朋友應該知道。不是所有的網(wǎng)站都是通過API請求數(shù)據(jù)填充網(wǎng)頁的。很多網(wǎng)站是服務端渲染,爬的時候就只能獲取到整個HTML網(wǎng)頁。這時候就需要使用正則把html標簽去掉。
有了上面的知識你很快就會寫出來: /<.+>/g。字符串replace方法替換成空格即可。很遺憾,這個是不行的,為什么呢?因為正則貪婪

<main>
    <header>斗破蒼穹</header>
    <article>炎帝</article>
    <footer>五帝破空</footer>
</main>
//這里會匹配到整個html,因為你會發(fā)現(xiàn)整個html也符合你寫的這個表達式呀

這時候機智的你可能會想到,<>里面是不能有<>的,那我可以這樣子:/<[^<>]+>/g。
是的,的確可行。但是你至少得想到這個特殊情況吧,難道以后每次都得想下,很是麻煩啊。其實有簡便的方法,那就是限定符后面加個?。即:/<.+?>/g,這就是懶惰模式
很好理解,就是匹配到就不繼續(xù)了。?本來就是代表0-1嘛(強行解釋一波O(∩_∩)O哈哈~)


PS: 所以有*?、+?、??、{n, m}?、{n, }?。是沒有{n}?滴

修飾符

為什么修飾符放在最后說呢?因為它最不起眼。最簡單。
就是加在正則最后面。

修飾符 描述
i ignoreCase執(zhí)行對大小寫不敏感的匹配。
g global執(zhí)行全局匹配(查找所有匹配而非在找到第一個匹配后停止)

有興趣可以自行看下多行模式,這里不提。

RegExp對象

既然是前端,自然得來點前端的

屬性

其實上面的修飾符也是RegExp屬性,比如

/\d/g.ignoreCase  // false
/\d/g.global // true

與修飾符無關的主要有倆

  1. source,返回正則表達式字符串形式
/^\d\\\.[0-9]$/g.source // "^\d\\\.[0-9]$"
  1. lastIndex,返回下一次開始搜索的位置,它是可讀寫的,注意只有帶g修飾符才有意義


方法

  1. test
    返回true or false,表示當前表達式能否匹配當前字符串
  2. exec
    匹配到的話以數(shù)組形式返回結(jié)果,成員是每一個匹配到的串,否則返回null

后記

最后來個考試。從jQuery拷了個正則解讀下

/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/

我看懂了,你們呢?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 注:本篇文章只為方便查看,特此保留,如有冒犯,敬請諒解?。?! 本文目標 30分鐘內(nèi)讓你明白正則表達式是什么,并對它...
    阿杰Alex閱讀 1,556評論 0 10
  • 正則表達式到底是什么東西?字符是計算機軟件處理文字時最基本的單位,可能是字母,數(shù)字,標點符號,空格,換行符,漢字等...
    獅子挽歌閱讀 2,271評論 0 9
  • 所有加粗的元字符的雙引號均為了方便表示,所有的正則表達式均在 ‘’ ——單引號中 “/b”:元字符,代表單詞的開始...
    哎呀_落錦繁華閱讀 329評論 0 0
  • 什么是正則表達式呢? 正則表達式(regular expression)描述了一種字符串匹配的模式,可以用來檢查一...
    chenxiaoer閱讀 454評論 0 1
  • 金是最先從震驚中反應過來的人。 他走到一具斷頭的尸體處,由于人早就死亡,所以頸部只有少量流血,傷口就像傳言一樣,是...
    永恒天火閱讀 241評論 0 0

友情鏈接更多精彩內(nèi)容