正則表達(dá)式 入門

原理

正則引擎

為什么正則能有效,因?yàn)橛幸妫@和為什么JS能執(zhí)行一樣偷厦,有JS引擎

正則的引擎大致可分為兩類:DFA和NFA

  • DFA (Deterministic finite automaton) 確定型有窮自動(dòng)機(jī)
  • NFA (Non-deterministic finite automaton) 非確定型有窮自動(dòng)機(jī)霹肝,大部分都是NFA

這里的“確定型”指申钩,對(duì)于某個(gè)確定字符的輸入叉袍,這臺(tái)機(jī)器的狀態(tài)會(huì)確定地從a跳到b始锚,“非確定型”指,對(duì)于某個(gè)確定字符的輸入喳逛,這臺(tái)機(jī)器可能有好幾種狀態(tài)的跳法瞧捌;這里的“有窮”指,狀態(tài)是有限的润文,可以在有限的步數(shù)內(nèi)確定某個(gè)字符串是被接受還是發(fā)好人卡的姐呐;這里的“自動(dòng)機(jī)”,可以理解為典蝌,一旦這臺(tái)機(jī)器的規(guī)則設(shè)定完成皮钠,就可以自行判斷了,不要人看赠法。

基礎(chǔ)知識(shí)

正則眼中的字符串——n個(gè)字符麦轰,n+1個(gè)位置

為什么要有字符還要有位置呢?因?yàn)槲恢檬强梢员黄ヅ涞摹?/p>

“占有字符”和“零寬度”:

  • 如果一個(gè)子正則表達(dá)式匹配到的是字符砖织,而不是位置款侵,而且會(huì)被保存到最終的結(jié)果中,那個(gè)這個(gè)子表達(dá)式就是占有字符的侧纯,比如 /ha/ (匹配 ha )就是占有字符的新锈;
  • 如果一個(gè)子正則匹配的是位置,而不是字符眶熬,或者匹配到的內(nèi)容不保存在結(jié)果中(其實(shí)也可以看做一個(gè)位置)妹笆,那么這個(gè)子表達(dá)式是零寬度的,比如 /read(?=ing)/ (匹配 reading 娜氏,但是只將read放入結(jié)果中拳缠,下文會(huì)詳述語(yǔ)法,此處僅僅舉例用)贸弥,其中的(?=ing)就是零寬度的窟坐,它本質(zhì)代表一個(gè)位置。

占有字符是互斥的绵疲,零寬度是非互斥的哲鸳。也就是一個(gè)字符,同一時(shí)間只能由一個(gè)子表達(dá)式匹配盔憨,而一個(gè)位置徙菠,卻可以同時(shí)由多個(gè)零寬度的子表達(dá)式匹配。舉個(gè)栗子郁岩,比如/aa/是匹配不了a的婿奔,這個(gè)字符串中的a只能由正則的第一個(gè)a字符匹配缺狠,而不能同時(shí)由第二個(gè)a匹配(廢話);但是位置是可以多個(gè)匹配的脸秽,比如/\b\ba/是可以匹配a的儒老,雖然正則表達(dá)式里有2個(gè)表示單詞開頭位置的\b元字符,這兩個(gè)\b是可以同時(shí)匹配位置0(在這個(gè)例子中)的

控制權(quán)和傳動(dòng)

控制權(quán)是指哪一個(gè)正則子表達(dá)式(可能為一個(gè)普通字符记餐、元字符或元字符序列組成)在匹配字符串驮樊,那么控制權(quán)就在哪。

傳動(dòng)是指正則引擎的一種機(jī)制片酝,傳動(dòng)裝置將定位正則從字符串的哪里開始匹配囚衔。

正則表達(dá)式當(dāng)開始匹配的時(shí)候,一般是由一個(gè)子表達(dá)式獲取控制權(quán)雕沿,從字符串中的某一個(gè)位置開始嘗試匹配练湿,一個(gè)子表達(dá)式開始嘗試匹配的位置,是從前一子表達(dá)匹配成功的結(jié)束位置開始的

語(yǔ)法

要用某類常見(jiàn)字符——簡(jiǎn)單元字符

  • '.' 匹配除了換行符以外的任意字符审轮,也即是[^\n]肥哎,如果要包含任意字符,可使用(.|\n)
  • \w (whatever) 匹配任意字母疾渣、數(shù)字或者下劃線篡诽,等價(jià)于[a-zA-Z0-9_],在deerchao的文中還指出可匹配漢字榴捡,但是\w在JS中是不能匹配漢字的
  • \s (space) 匹配任意空白符杈女,包含換頁(yè)符\f、換行符\n吊圾、回車符\r达椰、水平制表符\t、垂直制表符\v
  • \d 匹配數(shù)字
  • \un (Unicode) 匹配n项乒,這里的n是一個(gè)有4個(gè)十六進(jìn)制數(shù)字表示的Unicode字符啰劲,比如\u597d表示中文字符“好”,那么超過(guò)\uffff編號(hào)的字符怎么表示呢板丽?ES6的u修飾符會(huì)幫你呈枉。

要表示出現(xiàn)次數(shù)(重復(fù))——限定符

  • a*表示字符a連續(xù)出現(xiàn)次數(shù) >= 0 次
  • a+表示字符a連續(xù)出現(xiàn)次數(shù) >= 1 次
  • a?表示字符a出現(xiàn)次數(shù) 0 或 1 次
  • a{5}表示字符a連續(xù)出現(xiàn)次數(shù) 5 次
  • a{5,}表示字符a連續(xù)出現(xiàn)次數(shù) >= 5次
  • a{5,10}表示字符a連續(xù)出現(xiàn)次數(shù)為 5到10次 ,包括5和10

匹配位置——定位符和零寬斷言

  • \b 匹配單詞邊界位置埃碱,準(zhǔn)確的描述是它匹配一個(gè)位置,這個(gè)位置前后不全是\w能描述的字符酥泞,所以像\u597d\babc是可以匹配“好abc”的砚殿。
  • ^ 匹配字符串開始位置,也就是位置0芝囤,如果設(shè)置了 RegExp 對(duì)象的 Multiline 屬性似炎,^ 也匹配 '\n' 或 '\r' 之后的位置
  • $ 匹配字符串結(jié)束位置辛萍,如果設(shè)置了RegExp 對(duì)象的 Multiline 屬性刹帕,$ 也匹配 '\n' 或 '\r' 之前的位置

想表達(dá)“或”的意思——字符簇和分歧

字符簇可用來(lái)表達(dá)字符級(jí)別的“或”語(yǔ)義炒俱,表示的是方括號(hào)中的字符任選一:

  • [abc]表示a帘不、b键闺、c這3個(gè)字符中的任意一個(gè)褒傅,如果字母或者數(shù)字是連續(xù)的磺平,那么可以用-連起來(lái)表示创倔,[b-f]代表從b到f這么多字符中任選一個(gè)
  • [(ab)(cd)]并不會(huì)用來(lái)匹配字符串“ab”或“cd”翔脱,而是匹配a瘩扼、b谆甜、c、d集绰、(规辱、)這6個(gè)字符中的任一個(gè),也就是想表達(dá)“匹配字符串a(chǎn)b或者cd”這樣的需求不能這么做栽燕,要這么寫ab|cd罕袋。但這里要匹配圓括號(hào)本身,講道理是要反斜杠轉(zhuǎn)義的碍岔,但是在方括號(hào)中浴讯,圓括號(hào)被當(dāng)成普通字符看待,即便如此付秕,仍然建議顯式地轉(zhuǎn)義
  • 分歧用來(lái)表達(dá)表達(dá)式級(jí)別的“或”語(yǔ)義兰珍,表示的是匹配|左右任一表達(dá)就可:
    ab|cd會(huì)匹配字符串“ab”或者“cd”
  • 會(huì)短路,回想下編程語(yǔ)言中邏輯或的短路询吴,所以用(ab|abc)去匹配字符串“abc”掠河,結(jié)果會(huì)是“ab”,因?yàn)樨Q線左邊的已經(jīng)滿足了猛计,就用左邊的匹配結(jié)果代表整個(gè)正則的結(jié)果

想表達(dá)“非”的意思——反義

  • \W唠摹、\D、\S奉瘤、\B 用大寫字母的這幾個(gè)元字符表示就是對(duì)應(yīng)小寫字母匹配內(nèi)容的反義勾拉,這幾個(gè)依次匹配“除了字母、數(shù)字盗温、下劃線外的字符”藕赞、“非數(shù)字字符”、“非空白符”卖局、“非單詞邊界位置”
  • [aeiou]表示除了a斧蜕、e、i砚偶、o批销、u外的任一字符洒闸,在方括號(hào)中且出現(xiàn)在開頭位置的表示排除,如果在方括號(hào)中不出現(xiàn)在開頭位置均芽,那么它僅僅代表字符本身

貪婪和非貪婪

在限定符中丘逸,除了{(lán)n}確切表示重復(fù)幾次,其余的都是一個(gè)有下限的范圍掀宋。

在默認(rèn)的模式(貪婪)下深纲,會(huì)盡可能多的匹配內(nèi)容。比如用ab*去匹配字符串“abbb”布朦,結(jié)果是“abbb”囤萤。

而通過(guò)在限定符后面加問(wèn)號(hào)?可以進(jìn)行非貪婪匹配,會(huì)盡可能少地匹配是趴。用ab*?去匹配“abbb”涛舍,結(jié)果會(huì)是“a”。

不帶問(wèn)號(hào)的限定符也稱匹配優(yōu)先量詞唆途,帶問(wèn)號(hào)的限定符也稱忽略匹配優(yōu)先量詞富雅。

JS 中的正則

字面量, 構(gòu)造函數(shù)和工廠符號(hào)都是可以的:

         /pattern/flags
         new RegExp(pattern [, flags])
         RegExp(pattern [, flags])

參數(shù)
pattern
正則表達(dá)式的文本。
flags
如果指定肛搬,標(biāo)志可以具有以下值的任意組合:

  • g 全局匹配;找到所有匹配没佑,而不是在第一個(gè)匹配后停止

  • i 忽略大小寫

  • m 多行; 將開始和結(jié)束字符(^和$)視為在多行上工作(例如,分別匹配每一行的開始和結(jié)束(由 \n 或 \r 分割)温赔,而不只是只匹配整個(gè)輸入字符串的最開始和最末尾處蛤奢。

  • u Unicode; 將模式視為Unicode序列點(diǎn)的序列

  • y 粘性匹配; 僅匹配目標(biāo)字符串中此正則表達(dá)式的lastIndex屬性指示的索引(并且不嘗試從任何后續(xù)的索引匹配)。

有兩種方法來(lái)創(chuàng)建一個(gè)RegExp對(duì)象:一是字面量陶贼、二是構(gòu)造函數(shù)啤贩。要指示字符串,字面量的參數(shù)不使用引號(hào)拜秧,而構(gòu)造函數(shù)的參數(shù)使用引號(hào)痹屹。因此,以下表達(dá)式創(chuàng)建相同的正則表達(dá)式

        /ab+c/i;
        new RegExp('ab+c', 'i');
        new RegExp(/ab+c/, 'i');

方法

RegExp.prototype.exec()

exec() 方法在一個(gè)指定字符串中執(zhí)行一個(gè)搜索匹配枉氮。返回一個(gè)結(jié)果數(shù)組或 null志衍。

        var matches = /h./.exec('This is a hello world!');
        console.log(matches);        // [ 'hi', index: 1, input: 'This is a hello world!' ]

RegExp.prototype.test()

test() 方法執(zhí)行一個(gè)檢索,用來(lái)查看正則表達(dá)式與指定的字符串是否匹配聊替。返回 true 或 false楼肪。

當(dāng)你想要知道一個(gè)模式是否存在于一個(gè)字符串中時(shí),就可以使用 test()(類似于 String.prototype.search() 方法)惹悄,差別在于test返回一個(gè)布爾值淹辞,而 search 返回索引(如果找到)或者-1(如果沒(méi)找到)

        let str = 'hello world!';
        let result = /hello/.test(str);
        console.log(result);
        // true

例子

使用正則改變數(shù)據(jù)結(jié)構(gòu)

下例使用 replace 方法 (繼承自 String)去匹配姓名 first last 輸出新的格式 last, first。腳本中使用 $1 和 $2 指明括號(hào)里先前的匹配.

        var re = /(\w+)\s(\w+)/;
        var str = "John Smith";
        var newstr = str.replace(re, "$2, $1");
        print(newstr);          //"Smith, John"

在多行中使用正則表達(dá)式

        var s = "Please yes\nmake my day!";
        s.match(/yes.*day/);
        // Returns null
        s.match(/yes[^]*day/);
        // Returns 'yes\nmake my day'

使用正則表達(dá)式和 Unicode 字符

\w 或 \W 只會(huì)匹配基本的 ASCII 字符俘侠;如 'a' 到 'z'象缀、 'A' 到 'Z'、 0 到 9 及 '_'爷速。為了匹配其他語(yǔ)言中的字符央星,如西里爾(Cyrillic)或 希伯來(lái)語(yǔ)(Hebrew),要使用 \uhhhh惫东,"hhhh" 表示以十六進(jìn)制表示的字符的 Unicode 值

        var text = "Образец text на русском языке";
        var regex = /[\u0400-\u04FF]+/g;

        var match = regex.exec(text);
        print(match[1]);  // prints "Образец"
        print(regex.lastIndex);  // prints "7"

        var match2 = regex.exec(text);
        print(match2[1]);  // prints "на" [did not print "text"]
        print(regex.lastIndex);  // prints "15"

        // and so on

從 URL 中提取子域名

        var url = "http://xxx.domain.com";
        print(/[^.]+/.exec(url)[0].substr(7)); // prints "xxx"
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末莉给,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子廉沮,更是在濱河造成了極大的恐慌颓遏,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滞时,死亡現(xiàn)場(chǎng)離奇詭異叁幢,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)坪稽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門曼玩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人窒百,你說(shuō)我怎么就攤上這事黍判。” “怎么了篙梢?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵顷帖,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我渤滞,道長(zhǎng)贬墩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任蔼水,我火速辦了婚禮震糖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘趴腋。我一直安慰自己吊说,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布优炬。 她就那樣靜靜地躺著颁井,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蠢护。 梳的紋絲不亂的頭發(fā)上雅宾,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音葵硕,去河邊找鬼眉抬。 笑死贯吓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蜀变。 我是一名探鬼主播悄谐,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼库北!你這毒婦竟也來(lái)了爬舰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤寒瓦,失蹤者是張志新(化名)和其女友劉穎情屹,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體杂腰,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡垃你,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颈墅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜡镶。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖恤筛,靈堂內(nèi)的尸體忽然破棺而出官还,到底是詐尸還是另有隱情,我是刑警寧澤毒坛,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布望伦,位于F島的核電站,受9級(jí)特大地震影響煎殷,放射性物質(zhì)發(fā)生泄漏屯伞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一豪直、第九天 我趴在偏房一處隱蔽的房頂上張望劣摇。 院中可真熱鬧,春花似錦弓乙、人聲如沸末融。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)勾习。三九已至,卻和暖如春懈玻,著一層夾襖步出監(jiān)牢的瞬間巧婶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留艺栈,地道東北人英岭。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像眼滤,于是被迫代替她去往敵國(guó)和親巴席。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容