日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

正则表达式之 NFA 引擎匹配原理详解

發(fā)布時(shí)間:2023/12/3 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 正则表达式之 NFA 引擎匹配原理详解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 一、為什么要了解引擎匹配原理
  • 二、正則表達(dá)式引擎
  • 三、預(yù)備知識(shí)
    • (一)字符串組成
    • (二)占有字符和零寬度
    • (三)控制權(quán)和傳動(dòng)
  • 四、正則表達(dá)式簡(jiǎn)單匹本過(guò)程
    • (一)基礎(chǔ)匹配過(guò)程
    • (二)含有匹配優(yōu)先量詞的匹配過(guò)程
      • 匹配成功一
      • 匹配成功二
      • 匹配失敗
    • (三)含有忽略優(yōu)先量詞的匹配過(guò)程
      • 匹配成功
    • (四)零寬度匹配過(guò)程

一、為什么要了解引擎匹配原理

一個(gè)個(gè)音符雜亂無(wú)章的組合在一起,彈奏出的或許就是噪音,同樣的音符經(jīng)過(guò)作曲家的手,就可以譜出非常動(dòng)聽(tīng)的樂(lè)曲,一個(gè)演奏者同樣可以照著樂(lè)譜奏出動(dòng)聽(tīng)的樂(lè)曲,但他/她或許不知道該如何去改變音符的組合,使得樂(lè)曲更動(dòng)聽(tīng)。

作為正則的使用者也一樣,不懂正則引擎原理的情況下,同樣可以寫(xiě)出滿足需求的正則,但是不知道原理,卻很難寫(xiě)出高效且沒(méi)有隱患的正則。所以對(duì)于經(jīng)常使用正則,或是有興趣深入學(xué)習(xí)正則的人,還是有必要了解一下正則引擎的匹配原理的。

二、正則表達(dá)式引擎

正則引擎大體上可分為不同的兩類(lèi):DFA 和 NFA,而 NFA 又基本上可以分為傳統(tǒng)型 NFA 和 POSIX NFA。

  • DFA(Deterministic Finite Automaton) 確定型有窮自動(dòng)機(jī)

  • NFA(Non-deterministic finite automaton) 非確定型有窮自動(dòng)機(jī)
    ① Traditional NFA
    ② POSIX NFA

  • DFA 引擎因?yàn)椴恍枰厮?#xff0c;所以匹配快速,但不支持捕獲組,所以也就不支持反向引用和 $number 這種引用方式,目前使用 DFA 引擎的語(yǔ)言和工具主要有 awk、egrep 和 lex。

    POSIX NFA 主要指符合 POSIX 標(biāo)準(zhǔn)的NFA引擎,它的特點(diǎn)主要是提供 longest-leftmost 匹配,也就是在找到最左側(cè)最長(zhǎng)匹配之前,它將繼續(xù)回溯。同 DFA 一樣,非貪婪模式或者說(shuō)忽略優(yōu)先量詞對(duì)于 POSIX NFA 同樣是沒(méi)有意義的。

    大多數(shù)語(yǔ)言和工具使用的是傳統(tǒng)型的 NFA 引擎,它有一些 DFA 不支持的特性:

  • 捕獲組、反向引用和$number引用方式;

  • 環(huán)視(Lookaround,(?<=…)、(?<!…)、(?=…)、(?!…)),或者有的有文章叫做預(yù)搜索;

  • 忽略優(yōu)化量詞(??、*?、+?、{m,n}?、{m,}?),或者有的文章叫做非貪婪模式;

  • 占有優(yōu)先量詞(?+、*+、++、{m,n}+、{m,}+,目前僅 Java 和 PCRE 支持),固化分組(?>…)。

  • 引擎間的區(qū)別不是本文的重點(diǎn),僅做簡(jiǎn)要的介紹,有興趣的可參考相關(guān)文獻(xiàn)。

    三、預(yù)備知識(shí)

    (一)字符串組成


    對(duì)于字符串“abc”而言,包括三個(gè)字符和四個(gè)位置。

    (二)占有字符和零寬度

    正則表達(dá)式匹配過(guò)程中,如果子表達(dá)式匹配到的是字符內(nèi)容,而非位置,并被保存到最終的匹配結(jié)果中,那么就認(rèn)為這個(gè)子表達(dá)式是占有字符的;如果子表達(dá)式匹配的僅僅是位置,或者匹配的內(nèi)容并不保存到最終的匹配結(jié)果中,那么就認(rèn)為這個(gè)子表達(dá)式是零寬度的。

    占有字符是互斥的,零寬度是非互斥的。也就是一個(gè)字符,同一時(shí)間只能由一個(gè)子表達(dá)式匹配,而一個(gè)位置,卻可以同時(shí)由多個(gè)零寬度的子表達(dá)式匹配。

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

    正則的匹配過(guò)程,通常情況下都是由一個(gè)子表達(dá)式(可能為一個(gè)普通字符、元字符或元字符序列組成)取得控制權(quán),從字符串的某一位置開(kāi)始嘗試匹配,一個(gè)子表達(dá)式開(kāi)始嘗試匹配的位置,是從前一子表達(dá)匹配成功的結(jié)束位置開(kāi)始的。如正則表達(dá)式:

    (子表達(dá)式一)(子表達(dá)式二)

    假設(shè)(子表達(dá)式一)為零寬度表達(dá)式,由于它匹配開(kāi)始和結(jié)束的位置是同一個(gè),如位置 0,那么(子表達(dá)式二)是從位置 0 開(kāi)始嘗試匹配的。

    假設(shè)(子表達(dá)式一)為占有字符的表達(dá)式,由于它匹配開(kāi)始和結(jié)束的位置不是同一個(gè),如匹配成功開(kāi)始于位置 0,結(jié)束于位置 2,那么(子表達(dá)式二)是從位置 2 開(kāi)始嘗試匹配的。

    而對(duì)于整個(gè)表達(dá)式來(lái)說(shuō),通常是由字符串位置 0 開(kāi)始嘗試匹配的。如果在位置 0 開(kāi)始的嘗試,匹配到字符串某一位置時(shí)整個(gè)表達(dá)式匹配失敗,那么引擎會(huì)使正則向前傳動(dòng),整個(gè)表達(dá)式從位置1開(kāi)始重新嘗試匹配,依此類(lèi)推,直到報(bào)告匹配成功或嘗試到最后一個(gè)位置后報(bào)告匹配失敗。

    四、正則表達(dá)式簡(jiǎn)單匹本過(guò)程

    (一)基礎(chǔ)匹配過(guò)程


    源字符串:abc

    正則表達(dá)式:abc

    匹配過(guò)程:

    首先由字符“a”取得控制權(quán),從位置 0 開(kāi)始匹配,由“a”來(lái)匹配“a”,匹配成功,控制權(quán)交給字符“b”;由于“a”已被“a”匹配,所以“b”從位置 1 開(kāi)始嘗試匹配,由“b”來(lái)匹配“b”,匹配成功,控制權(quán)交給“c”;由“c”來(lái)匹配“c”,匹配成功。

    此時(shí)正則表達(dá)式匹配完成,報(bào)告匹配成功。匹配結(jié)果為“abc”,開(kāi)始位置為 0,結(jié)束位置為 3。

    (二)含有匹配優(yōu)先量詞的匹配過(guò)程

    匹配成功一


    源字符串:abc

    正則表達(dá)式:ab?c

    量詞“?”屬于匹配優(yōu)先量詞,在可匹配可不匹配時(shí),會(huì)先選擇嘗試匹配,只有這種選擇會(huì)使整個(gè)表達(dá)式無(wú)法匹配成功時(shí),才會(huì)嘗試讓出匹配到的內(nèi)容。這里的量詞“?”是用來(lái)修飾字符“b”的,所以“b?”是一個(gè)整體。

    匹配過(guò)程:

    首先由字符“a”取得控制權(quán),從位置 0 開(kāi)始匹配,由“a”來(lái)匹配“a”,匹配成功,控制權(quán)交給字符“b?”;由于“?”是匹配優(yōu)先量詞,所以會(huì)先嘗試進(jìn)行匹配,由“b?”來(lái)匹配“b”,匹配成功,控制權(quán)交給“c”,同時(shí)記錄一個(gè)備選狀態(tài);由“c”來(lái)匹配“c”,匹配成功。記錄的備選狀態(tài)丟棄。

    此時(shí)正則表達(dá)式匹配完成,報(bào)告匹配成功。匹配結(jié)果為“abc”,開(kāi)始位置為 0,結(jié)束位置為 3。

    匹配成功二


    源字符串:ac

    正則表達(dá)式:ab?c

    匹配過(guò)程:

    首先由字符“a”取得控制權(quán),從位置 0 開(kāi)始匹配,由“a”來(lái)匹配“a”,匹配成功,控制權(quán)交給字符“b?”;先嘗試進(jìn)行匹配,由“b?”來(lái)匹配“c”,同時(shí)記錄一個(gè)備選狀態(tài),匹配失敗,此時(shí)進(jìn)行回溯,找到備選狀態(tài),“b?”忽略匹配,讓出控制權(quán),把控制權(quán)交給“c”;由“c”來(lái)匹配“c”,匹配成功。

    此時(shí)正則表達(dá)式匹配完成,報(bào)告匹配成功。匹配結(jié)果為“ac”,開(kāi)始位置為 0,結(jié)束位置為 2。其中“b?”不匹配任何內(nèi)容。

    匹配失敗


    源字符串:abd

    正則表達(dá)式:ab?c

    匹配過(guò)程:

    首先由字符“a”取得控制權(quán),從位置 0 開(kāi)始匹配,由“a”來(lái)匹配“a”,匹配成功,控制權(quán)交給字符“b?”;先嘗試進(jìn)行匹配,由“b?”來(lái)匹配“b”,同時(shí)記錄一個(gè)備選狀態(tài),匹配成功,控制權(quán)交給“c”;由“c”來(lái)匹配“d”,匹配失敗,此時(shí)進(jìn)行回溯,找到記錄的備選狀態(tài),“b?”忽略匹配,即“b?”不匹配“b”,讓出控制權(quán),把控制權(quán)交給“c”;由“c”來(lái)匹配“b”,匹配失敗。此時(shí)第一輪匹配嘗試失敗。

    正則引擎使正則向前傳動(dòng),由位置 1 開(kāi)始嘗試匹配,由“a”來(lái)匹配“b”,匹配失敗,沒(méi)有備選狀態(tài),第二輪匹配嘗試失敗。

    繼續(xù)向前傳動(dòng),直到在位置 3 嘗試匹配失敗,匹配結(jié)束。此時(shí)報(bào)告整個(gè)表達(dá)式匹配失敗。

    (三)含有忽略優(yōu)先量詞的匹配過(guò)程

    匹配成功


    源字符串:abc

    正則表達(dá)式:ab??c

    量詞“??”屬于忽略優(yōu)先量詞,在可匹配可不匹配時(shí),會(huì)先選擇不匹配,只有這種選擇會(huì)使整個(gè)表達(dá)式無(wú)法匹配成功時(shí),才會(huì)嘗試進(jìn)行匹配。這里的量詞“??”是用來(lái)修飾字符“b”的,所以“b??”是一個(gè)整體。

    匹配過(guò)程:

    首先由字符“a”取得控制權(quán),從位置 0 開(kāi)始匹配,由“a”來(lái)匹配“a”,匹配成功,控制權(quán)交給字符“b??”;先嘗試忽略匹配,即“b??”不進(jìn)行匹配,同時(shí)記錄一個(gè)備選狀態(tài),控制權(quán)交給“c”;由“c”來(lái)匹配“b”,匹配失敗,此時(shí)進(jìn)行回溯,找到記錄的備選狀態(tài),“b??”嘗試匹配,即“b??”來(lái)匹配“b”,匹配成功,把控制權(quán)交給“c”;由“c”來(lái)匹配“c”,匹配成功。

    此時(shí)正則表達(dá)式匹配完成,報(bào)告匹配成功。匹配結(jié)果為“abc”,開(kāi)始位置為 0,結(jié)束位置為 3。其中“b??”匹配字符“b”。

    (四)零寬度匹配過(guò)程


    源字符串:a12

    正則表達(dá)式:^(?=[a-z])[a-z0-9]+$

    元字符“^”和“$”匹配的只是位置,順序環(huán)視“(?=[a-z])”只進(jìn)行匹配,并不占有字符,也不將匹配的內(nèi)容保存到最終的匹配結(jié)果,所以都是零寬度的。

    這個(gè)正則的意義就是匹配由字母或數(shù)字組成的,第一個(gè)字符是字母的字符串。

    匹配過(guò)程:

    首先由元字符“^”取得控制權(quán),從位置 0 開(kāi)始匹配,“^”匹配的就是開(kāi)始位置“位置 0”,匹配成功,控制權(quán)交給順序環(huán)視“(?=[a-z])”;

    (?=[a-z])”要求它所在位置右側(cè)必須是字母才能匹配成功,零寬度的子表達(dá)式之間是不互斥的,即同一個(gè)位置可以同時(shí)由多個(gè)零寬度子表達(dá)式匹配,所以它也是從位置 0 嘗試進(jìn)行匹配,位置 0 的右側(cè)是字符“a”,符合要求,匹配成功,控制權(quán)交給“[a-z0-9]+”;

    因?yàn)椤?font color="#e36c0a">(?=[a-z])”只進(jìn)行匹配,并不將匹配到的內(nèi)容保存到最后結(jié)果,并且“(?=[a-z])”匹配成功的位置是位置 0,所以“[a-z0-9]+”也是從位置 0 開(kāi)始嘗試匹配的,“[a-z0-9]+”首先嘗試匹配“a”,匹配成功,繼續(xù)嘗試匹配,可以成功匹配接下來(lái)的“1”和“2”,此時(shí)已經(jīng)匹配到位置 3,位置 3 的右側(cè)已沒(méi)有字符,這時(shí)會(huì)把控制權(quán)交給“$”;

    元字符“$”從位置 3 開(kāi)始嘗試匹配,它匹配的是結(jié)束位置,也就是“位置 3”,匹配成功。

    此時(shí)正則表達(dá)式匹配完成,報(bào)告匹配成功。匹配結(jié)果為“a12”,開(kāi)始位置為 0,結(jié)束位置為 3。其中“^”匹配位置 0,“(?=[a-z])”匹配位置 0,“[a-z0-9]+”匹配字符串“a12”,“$”匹配位置 3。

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

    總結(jié)

    以上是生活随笔為你收集整理的正则表达式之 NFA 引擎匹配原理详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。