導航:首頁 > 編程語言 > 正則表達式轉NFA代碼

正則表達式轉NFA代碼

發布時間:2024-02-03 18:38:07

1. 如何將正則表達式轉換為NFA

正則表達式轉換NFA演算法

基礎的正則表達式:


2. 請問java中正則表達式匹配怎麼實現的!

Java中正則表達式匹配的語法規則:

packageorg.luosijin.test;
importjava.util.regex.Matcher;
importjava.util.regex.Pattern;

/**
*正則表達式
*@versionV5.0
*@authorAdmin
*@date2015-7-25
*/
publicclassRegex{

/**
*@paramargs
*@authorAdmin
*@date2015-7-25
*/

publicstaticvoidmain(String[]args){
Patternpattern=Pattern.compile("b*g");
Matchermatcher=pattern.matcher("bbg");
System.out.println(matcher.matches());
System.out.println(pattern.matches("b*g","bbg"));
//驗證郵政編碼
System.out.println(pattern.matches("[0-9]{6}","200038"));
System.out.println(pattern.matches("//d{6}","200038"));
//驗證電話號碼
System.out.println(pattern.matches("[0-9]{3,4}//-?[0-9]+","02178989799"));
getDate("Nov10,2009");
charReplace();
//驗證身份證:判斷一個字元串是不是身份證號碼,即是否是15或18位數字。
System.out.println(pattern.matches("^//d{15}|//d{18}$","123456789009876"));
getString("D:/dir1/test.txt");
getChinese("welcometochina,江西奉新,welcome,你!");
validateEmail("[email protected]");
}
/**
*日期提取:提取出月份來
*@paramstr
*@authorAdmin
*@date2015-7-25
*/
publicstaticvoidgetDate(Stringstr){
StringregEx="([a-zA-Z]+)|//s+[0-9]{1,2},//s*[0-9]{4}";
Patternpattern=Pattern.compile(regEx);
Matchermatcher=pattern.matcher(str);
if(!matcher.find()){
System.out.println("日期格式錯誤!");
return;
}
System.out.println(matcher.group(1));//分組的索引值是從1開始的,所以取第一個分組的方法是m.group(1)而不是m.group(0)。
}
/**
*字元替換:本實例為將一個字元串中所有包含一個或多個連續的「a」的地方都替換成「A」。
*
*@authorAdmin
*@date2015-7-25
*/
publicstaticvoidcharReplace(){
Stringregex="a+";
Patternpattern=Pattern.compile(regex);
Matchermatcher=pattern.matcher("okaaaaLetmeAseeaaaaabooa");
Strings=matcher.replaceAll("A");
System.out.println(s);
}
/**
*字元串提取
*@paramstr
*@authorAdmin
*@date2015-7-25
*/
publicstaticvoidgetString(Stringstr){
Stringregex=".+/(.+)$";
Patternpattern=Pattern.compile(regex);
Matchermatcher=pattern.matcher(str);
if(!matcher.find()){
System.out.println("文件路徑格式不正確!");
return;
}
System.out.println(matcher.group(1));
}
/**
*中文提取
*@paramstr
*@authorAdmin
*@date2015-7-25
*/
publicstaticvoidgetChinese(Stringstr){
Stringregex="[//u4E00-//u9FFF]+";//[//u4E00-//u9FFF]為漢字
Patternpattern=Pattern.compile(regex);
Matchermatcher=pattern.matcher(str);
StringBuffersb=newStringBuffer();
while(matcher.find()){
sb.append(matcher.group());
}
System.out.println(sb);
}
/**
*驗證Email
*@paramemail
*@authorAdmin
*@date2015-7-25
*/
publicstaticvoidvalidateEmail(Stringemail){
Stringregex="[0-9a-zA-Z]+@[0-9a-zA-Z]+//.[0-9a-zA-Z]+";
Patternpattern=Pattern.compile(regex);
Matchermatcher=pattern.matcher(email);
if(matcher.matches()){
System.out.println("這是合法的Email");
}else{
System.out.println("這是非法的Email");
}
}
}

3. 正則表達式

首先我們要了解正則表達式是什麼,它是一種匹配模式, 不僅能匹配匹配字元,還能匹配位置 ,不少人忽略了匹配字元這個作用,往往碰到這種問題就手足無措。

如果正則只有精確匹配是沒有多大意義的,比如:

正則表達式的強大之處在於它的模糊匹配,分為橫向模糊和縱向模糊

橫向模糊:一個正則可匹配的字元串的長度不是固定的,可以是多種情況的
其實現的方式是使用量詞:

比如:

橫向模糊匹配到了多種情況,案例中用的正則是/ab{2,5}c/g,後面多了g,它是正則的一個修飾符。表示全局匹配,即在目標字元串中按順序找到滿足匹配模式的所有子串,強調的是「所有」,而不只是「第一個」。

縱向模糊:一個正則匹配的字元串,具體到某一位字元時,它可以不是某個確定的字元,可以有多種可能
其實現的方式是使用范圍類

-表示連字元,在此處作特殊用處,但是如果我要匹配'a-z'這三個字元呢?可以這么寫:

這樣引擎就不會認為它們是一個氛圍了, 符號在范圍類中起取反的作用, a表示除了a的所有字元。

系統根據范圍類又預定義了一些類方便我們使用:

不加g就是惰性匹配,我匹配完一個就不敢了,懶得再干其他事兒了,加了g就是貪婪模式了,我現在精力無限,會盡可能的幹事兒,但是我還有些理智,不會干超出能力之外的事兒,比如你給我的范圍是{2,5},我會盡可能做5件事兒,但是不會超過5件事,反正只要在能力范圍內,越多越好

此時我既想盡可能的匹配又想讓它不那麼貪婪有沒有辦法呢?辦法是有的, 貪婪模式一般作用在量詞這里,限制在量詞這里就好了 ,可以在量詞這里加一個?即可搞定。

其中/d{2,5}?/表示,雖然2到5次都行,當2個就夠的時候,就不在往下嘗試了。
此時就達到了我們的要求,不過這里完全是為了講解貪婪模式和惰性模式,並不推薦這么做,我完全可以將{2,5}改成{2},一樣的效果

知道了惰性模式的原理,我們完全可以鼓搗出其他的各式各樣的情形:

一個模式可以實現橫向和縱向模糊匹配。而多選分支可以支持多個子模式任選其一
具體形式如下:(p1|p2|p3),其中p1、p2和p3是子模式,用「|」(管道符)分隔,表示其中任何之一

但有個事實我們應該注意,比如我用/good|goodbye/,去匹配"goodbye"字元串時,結果是"good"

而把正則改成/goodbye|good/,結果是

也就是說,分支結構也是惰性的,即當前面的分支匹配上了,後面的就不再嘗試了

並且,使用分支的時候注意使用括弧,

匹配字元,無非就是范圍類、量詞和分支結構的組合使用罷了

分析:

表示一個16進制字元,可以用范圍類[0-9a-fA-F]
其中字元可以出現3或6次,需要是用量詞和分支結構
使用分支結構時,需要注意順序(惰性)

分析:
對每個地方的數字進行分析:
共4位數字,第一位數字可以為[0-2]。
當第1位為2時,第2位可以為[0-3],其他情況時,第2位為[0-9]。
第3位數字為[0-5],第4位為[0-9]

如果也要求匹配7:9,也就是說時分前面的0可以省略:

分析:
年,四位數字即可,可用[0-9]{4}。

月,共12個月,分兩種情況01、02、……、09和10、11、12,可用(0[1-9]|1[0-2])。

日,最大31天,可用(0[1-9]|[12][0-9]|3[01])

分析:
整體模式是: 盤符:文件夾文件夾文件夾
其中匹配F:,需要使用[a-zA-Z]:,其中盤符不區分大小寫,注意字元需要轉義。

文件名或者文件夾名,不能包含一些特殊字元,此時我們需要排除范圍類[ :*<>|"? /]來表示合法字元。另外不能為空名,至少有一個字元,也就是要使用量詞+。因此匹配「文件夾」,可用[ :*<>|"? /]+。

另外「文件夾」,可以出現任意次。也就是([^: <>|"? /]+) 。其中括弧提供子表達式。

路徑的最後一部分可以是「文件夾」,沒有,因此需要添加([^:*<>|"? /]+)?。

最後拼接成了一個看起來比較復雜的正則:

用到了惰性匹配,防止把class也提取出來

優化:

^(脫字元)匹配開頭,在多行匹配中匹配行開頭。

$(美元符號)匹配結尾,在多行匹配中匹配行結尾

比如我們把字元串的開頭和結尾用"#"替換(位置可以替換成字元的!):

多行匹配模式時,二者是行的概念,這個需要我們的注意

是單詞邊界,具體就是w和W之間的位置,也包括w和^之間的位置,也包括w和$之間的位置

首先,我們知道,w是范圍類[0-9a-zA-Z_]的簡寫形式,即w是字母數字或者下劃線的中任何一個字元。而W是排除范圍類[^0-9a-zA-Z_]的簡寫形式,即W是w以外的任何一個字元

此時我們可以看看"[#JS#] #Lesson_01#.#mp4#"中的每一個"#",是怎麼來的。

第一個"#",兩邊是"["與"J",是W和w之間的位置。

第二個"#",兩邊是"S"與"]",也就是w和W之間的位置。

第三個"#",兩邊是空格與"L",也就是W和w之間的位置。

第四個"#",兩邊是"1"與".",也就是w和W之間的位置。

第五個"#",兩邊是"."與"m",也就是W和w之間的位置。

第六個"#",其對應的位置是結尾,但其前面的字元"4"是w,即w和$之間的位置。

知道了的概念後,那麼B也就相對好理解了。

B就是的反面的意思,非單詞邊界。例如在字元串中所有位置中,扣掉,剩下的都是B的。

具體說來就是w與w、W與W、^與W,W與$之間的位置

exp1(?=exp2) 表達式會匹配exp1表達式,但只有其後面內容是exp2的時候才會匹配

exp1(?=exp2) 表達式會匹配exp1表達式,但只有其後面內容不是exp2的時候才會匹配

(?=p),其中p是一個子模式,即p前面的位置
比如(?=l),表示'l'字元前面的位置,例如:

而(?!p)就是(?=p)的反面意思

對於位置的理解,我們可以理解成空字元""

因此,把/ hello$/寫成/ ^hello$$$/,是沒有任何問題的:

也就是說字元之間的位置,可以寫成多個。

把位置理解空字元,是對位置非常有效的理解方式

此正則要求只有一個字元,但該字元後面是開頭。

比如把"12345678",變成"12,345,678"。

可見是需要把相應的位置替換成","

使用(?=d{3}$)就可以做到:

因為逗號出現的位置,要求後面3個數字一組,也就是d{3}至少出現一次。

此時可以使用量詞+:

此時會出現問題:

上面的正則,僅僅表示把從結尾向前數,一但是3的倍數,就把其前面的位置替換成逗號

怎麼解決呢?我們要求匹配的到這個位置不能是開頭。

我們知道匹配開頭可以使用^,但要求這個位置不是開頭怎麼辦?

easy,(?!^)

如果要把"12345678 123456789"替換成"12,345,678 123,456,789"。

此時我們需要修改正則,把裡面的開頭^和結尾$,替換成

其中(?!)怎麼理解呢?

要求當前是一個位置,但不是前面的位置,其實(?!)說的就是B。

因此最終正則變成了:/B(?=(d{3})+)/g

此題,如果寫成多個正則來判斷,比較容易。但要寫成一個正則就比較困難。

那麼,我們就來挑戰一下。看看我們對位置的理解是否深刻

我們可以把原題變成下列幾種情況之一:

1.同時包含數字和小寫字母

2.同時包含數字和大寫字母

3.同時包含小寫字母和大寫字母

4.同時包含數字、小寫字母和大寫字母

上面的正則看起來比較復雜,只要理解了第二步,其餘就全部理解了。

/(?=.*[0-9])^[0-9A-Za-z]{6,12}$/

對於這個正則,我們只需要弄明白(?=.*[0-9])^即可。

分開來看就是(?=.*[0-9])和^。

表示開頭前面還有個位置(當然也是開頭,即同一個位置,想想之前的空字元類比)。

(?=. [0-9])表示該位置後面的字元匹配. [0-9],即,有任何多個任意字元,後面再跟個數字。

另一種解法:
「至少包含兩種字元」的意思就是說,不能全部都是數字,也不能全部都是小寫字母,也不能全部都是大寫字母。

那麼要求「不能全部都是數字」,怎麼做呢?(?!p)出馬!

三種'都不能'呢?

1.分組和分支結構

括弧是提供分組功能,使量詞'+'作用於z和這個整體

而在多選分支結構(p1|p2)中,此處括弧的作用也是不言而喻的,提供了子表達式的所有可能

而要使用它帶來的好處,必須配合使用實現環境的API

以日期為例。假設格式是yyyy-mm-dd的

提取數據:

match返回的一個數組,第一個元素是整體匹配結果,然後是各個分組(括弧里)匹配的內容,然後是匹配下標,最後是輸入的文本

可以使用正則對象的exec方法:

也可以使用構造函數的全局屬性$1至$9來獲取:

替換:

想把yyyy-mm-dd格式,替換成mm/dd/yyyy怎麼做?

反向引用:

比如要寫一個正則支持匹配如下三種格式:

注意裡面的1,表示的引用之前的那個分組(-|/|.)。不管它匹配到什麼(比如-),1都匹配那個同樣的具體某個字元

括弧嵌套怎麼辦?

以左括弧(開括弧)為准

10是表示第10個分組,還是1和0呢?答案是前者,雖然一個正則里出現10比較罕見

引用不存在的分組會怎樣?

因為反向引用,是引用前面的分組,但我們在正則里引用了不存在的分組時,此時正則不會報錯,只是匹配反向引用的字元本身。例如2,就匹配"2"。注意"2"表示對2進行了轉意

非捕獲分組:

之前文中出現的分組,都會捕獲它們匹配到的數據,以便後續引用,因此也稱他們是捕獲型分組。

如果只想要括弧最原始的功能,但不會引用它,即,既不在API里引用,也不在正則里反向引用。此時可以使用非捕獲分組(?:p)

第二種,匹配整個字元串,然後用引用來提取出相應的數據

思路是找到每個單詞的首字母,當然這里不使用非捕獲匹配也是可以的

首字母不會轉化為大寫的。其中分組(.)表示首字母,單詞的界定,前面的字元可以是多個連字元、下劃線以及空白符。正則後面的?的目的,是為了應對str尾部的字元可能不是單詞字元,比如str是'-moz-transform '

通過key獲取相應的分組引用,然後作為對象的鍵

匹配一個開標簽,可以使用正則<[^>]+>,

匹配一個閉標簽,可以使用</[^>]+>,

但是要求匹配成對標簽,那就需要使用反向引用

其中開標簽<[ >]+>改成<([ >]+)>,使用括弧的目的是為了後面使用反向引用,而提供分組。閉標簽使用了反向引用,</1>。

另外[dD]的意思是,這個字元是數字或者不是數字,因此,也就是匹配任意字元的意思

而當目標字元串是"abbbc"時,就沒有所謂的「回溯」。其匹配過程是:

其中子表達式b{1,3}表示「b」字元連續出現1到3次。

圖中第5步有紅顏色,表示匹配不成功。此時b{1,3}已經匹配到了2個字元「b」,准備嘗試第三個時,結果發現接下來的字元是「c」。那麼就認為b{1,3}就已經匹配完畢。然後狀態又回到之前的狀態(即第6步,與第4步一樣),最後再用子表達式c,去匹配字元「c」。當然,此時整個表達式匹配成功了。

圖中的第6步,就是「回溯」。

你可能對此沒有感覺,這里我們再舉一個例子。正則是:

目標字元串是"abbbc",匹配過程是:

其中第7步和第10步是回溯。第7步與第4步一樣,此時b{1,3}匹配了兩個"b",而第10步與第3步一樣,此時b{1,3}只匹配了一個"b",這也是b{1,3}的最終匹配結果。

這里再看一個清晰的回溯,正則是:

目標字元串是:"acd"ef,匹配過程是:

圖中省略了嘗試匹配雙引號失敗的過程。可以看出「.*」是非常影響效率的。

為了減少一些不必要的回溯,可以把正則修改為/"[^"]*"/。

正則表達式匹配字元串的這種方式,有個學名,叫回溯法。

回溯法也稱試探法,它的基本思想是: 從問題的某一種狀態(初始狀態)出發,搜索從這種狀態出發所能達到的所有「狀態」,當一條路走到「盡頭」的時候(不能再前進),再後退一步或若干步,從另一種可能「狀態」出發,繼續搜索,直到所有的「路徑」(狀態)都試探過。這種不斷「前進」、不斷「回溯」尋找解的方法,就稱作「回溯法」

本質上就是深度優先搜索演算法。其中 退到之前的某一步這一過程,我們稱為「回溯」 。從上面的描述過程中,可以看出,路走不通時,就會發生「回溯」。即, 嘗試匹配失敗時,接下來的一步通常就是回溯

道理,我們是懂了。那麼JS中正則表達式會產生回溯的地方都有哪些呢?

3.1 貪婪量詞

之前的例子都是貪婪量詞相關的。比如b{1,3},因為其是貪婪的,嘗試可能的順序是從多往少的方向去嘗試。首先會嘗試"bbb",然後再看整個正則是否能匹配。不能匹配時,吐出一個"b",即在"bb"的基礎上,再繼續嘗試。如果還不行,再吐出一個,再試。如果還不行呢?只能說明匹配失敗了。

雖然局部匹配是貪婪的,但也要滿足整體能正確匹配。否則,皮之不存,毛將焉附?

此時我們不禁會問,如果當多個貪婪量詞挨著存在,並相互有沖突時,此時會是怎樣?

答案是,先下手為強!因為深度優先搜索。測試如下:

其中,前面的d{1,3}匹配的是"123",後面的d{1,3}匹配的是"45"。

3.2 惰性量詞
惰性量詞就是在貪婪量詞後面加個問號。表示盡可能少的匹配,比如:

其中d{1,3}?只匹配到一個字元"1",而後面的d{1,3}匹配了"234"。

雖然惰性量詞不貪,但也會有回溯的現象。比如正則是:

目標字元串是"12345",匹配過程是:

知道你不貪、很知足,但是為了整體匹配成,沒辦法,也只能給你多塞點了。因此最後d{1,3}?匹配的字元是"12",是兩個數字,而不是一個。

3.3 分支結構

我們知道分支也是惰性的,比如/can|candy/,去匹配字元串"candy",得到的結果是"can",因為分支會一個一個嘗試,如果前面的滿足了,後面就不會再試驗了。

分支結構,可能前面的子模式會形成了局部匹配,如果接下來表達式整體不匹配時,仍會繼續嘗試剩下的分支。這種嘗試也可以看成一種回溯。

比如正則:

目標字元串是"candy",匹配過程:

上面第5步,雖然沒有回到之前的狀態,但仍然回到了分支結構,嘗試下一種可能。所以,可以認為它是一種回溯的

簡單總結就是,正因為有多種可能,所以要一個一個試。直到,要麼到某一步時,整體匹配成功了;要麼最後都試完後,發現整體匹配不成功。

既然有回溯的過程,那麼匹配效率肯定低一些。相對誰呢?相對那些DFA引擎。

而JS的正則引擎是NFA,NFA是「非確定型有限自動機」的簡寫。

大部分語言中的正則都是NFA,為啥它這么流行呢?

答:你別看我匹配慢,但是我編譯快啊,而且我還有趣哦。

而在正則表達式中,操作符都體現在結構中,即由特殊字元和普通字元所代表的一個個特殊整體。

JS正則表達式中,都有哪些結構呢?

其中涉及到的操作符有:

上面操作符的優先順序從上至下,由高到低。

這里,我們來分析一個正則:

因為是要匹配整個字元串,我們經常會在正則前後中加上錨字元^和$。

比如要匹配目標字元串"abc"或者"bcd"時,如果一不小心,就會寫成/^abc|bcd$/。

而位置字元和字元序列優先順序要比豎杠高,故其匹配的結構是:

應該修改成:

2.2 量詞連綴問題

假設,要匹配這樣的字元串:

此時正則不能想當然地寫成/^[abc]{3}+$/,這樣會報錯,說「+」前面沒什麼可重復的:
此時要修改成:

2.3 元字元轉義問題
所謂元字元,就是正則中有特殊含義的字元。

所有結構里,用到的元字元總結如下:

當匹配上面的字元本身時,可以一律轉義:

在string中,也可以把每個字元轉義,當然,轉義後的結果仍是本身:

現在的問題是,是不是每個字元都需要轉義呢?否,看情況。

2.3.1 范圍類中的元字元

跟范圍類相關的元字元有 []、^、- 。因此在會引起歧義的地方進行轉義。例如開頭的^必須轉義,不然會把整個范圍類,看成反義范圍類。

2.3.2 匹配「[abc]」和「{3,5}」

我們知道[abc],是個字元組。如果要匹配字元串"[abc]"時,該怎麼辦?

可以寫成/[abc]/,也可以寫成/[abc]/,測試如下:

只需要在第一個方括弧轉義即可,因為後面的方括弧構不成字元組,正則不會引發歧義,自然不需要轉義。

同理,要匹配字元串"{3,5}",只需要把正則寫成/{3,5}/即可。

另外,我們知道量詞有簡寫形式{m,},卻沒有{,n}的情況。雖然後者不構成量詞的形式,但此時並不會報錯。當然,匹配的字元串也是"{,n}",測試如下:

var str = "{,3}";
var reg = /{,3}/g;
console.log( str.match(reg)[0] );
// => "{,3}"

2.3.3 其餘情況

比如= ! : - ,等符號,只要不在特殊結構中,也不需要轉義。

但是,括弧需要前後都轉義的,如/(123)/。

至於剩下的^ $ . * + ? | /等字元,只要不在字元組內,都需要轉義的。

因為豎杠「|」,的優先順序最低,所以正則分成了兩部分d{15}和d{17}[dxX]。

d{15}表示15位連續數字。
d{17}[dxX]表示17位連續數字,最後一位可以是數字可以大小寫字母"x"。
可視化如下:

3.2 IPV4地址

正則表達式是:

這個正則,看起來非常嚇人。但是熟悉優先順序後,會立馬得出如下的結構:

((...).){3}(...)

上面的兩個(...)是一樣的結構。表示匹配的是3位數字。因此整個結構是

3位數.3位數.3位數.3位數
然後再來分析(...):

(0{0,2}d|0?d{2}|1d{2}|2[0-4]d|25[0-5])

它是一個多選結構,分成5個部分:

0{0,2}d ,匹配一位數,包括0補齊的。比如,9、09、009;
0?d{2} ,匹配兩位數,包括0補齊的,也包括一位數;
1d{2} ,匹配100到199;
2[0-4]d ,匹配200-249;
25[0-5] ,匹配250-255。
最後來看一下其可視化形式:

掌握正則表達式中的優先順序後,再看任何正則應該都有信心分析下去了。

至於例子,不一而足,沒有寫太多。

這里稍微總結一下,豎杠的優先順序最低,即最後運算。

只要知道這一點,就能讀懂大部分正則。

另外關於元字元轉義問題,當自己不確定與否時,盡管去轉義,總之是不會錯的。

本文就解決該問題,內容包括:

2.1 是否能使用正則

正則太強大了,以至於我們隨便遇到一個操作字元串問題時,都會下意識地去想,用正則該怎麼做。但我們始終要提醒自己,正則雖然強大,但不是萬能的,很多看似很簡單的事情,還是做不到的。

比如匹配這樣的字元串:1010010001....

雖然很有規律,但是只靠正則就是無能為力。

2.2 是否有必要使用正則

要認識到正則的局限,不要去研究根本無法完成的任務。同時,也不能走入另一個極端:無所不用正則。能用字元串API解決的簡單問題,就不該正則出馬。

比如,從日期中提取出年月日,雖然可以使用正則:

其實,可以使用字元串的split方法來做,即可:

比如,判斷是否有問號,雖然可以使用:

其實,可以使用字元串的indexOf方法:

比如獲取子串,雖然可以使用正則:

其實,可以直接使用字元串的substring或substr方法來做:

var str = "JavaScript";
console.log( str.substring(4) );
// => Script

2.3 是否有必要構建一個復雜的正則

比如密碼匹配問題,要求密碼長度6-12位,由數字、小寫字元和大寫字母組成,但必須至少包括2種字元。

在匹配位置那篇文章里,我們寫出了正則是:

其實可以使用多個小正則來做:

所謂准確性,就是能匹配預期的目標,並且不匹配非預期的目標。

這里提到了「預期」二字,那麼我們就需要知道目標的組成規則。

不然沒法界定什麼樣的目標字元串是符合預期的,什麼樣的又不是符合預期的。

下面將舉例說明,當目標字元串構成比較復雜時,該如何構建正則,並考慮到哪些平衡。

3.1 匹配固定電話

比如要匹配如下格式的固定電話號碼:

055188888888 0551-88888888 (0551)88888888
第一步,了解各部分的模式規則。

上面的電話,總體上分為區號和號碼兩部分(不考慮分機號和+86的情形)。

區號是0開頭的3到4位數字,對應的正則是:0d{2,3}

號碼是非0開頭的7到8位數字,對應的正則是:[1-9]d{6,7}

因此,匹配055188888888的正則是:/^0d{2,3}[1-9]d{6,7}$/

匹配0551-88888888的正則是:/^0d{2,3}-[1-9]d{6,7}$/

匹配(0551)88888888的正則是:/^(0d{2,3})[1-9]d{6,7}$/

第二步,明確形式關系。

這三者情形是或的關系,可以構建分支:

提取公共部分:

進一步簡寫:

上面的正則構建過程略顯羅嗦,但是這樣做,能保證正則是准確的。

上述三種情形是或的關系,這一點很重要,不然很容易按字元是否出現的情形把正則寫成:

/^(?0d{2,3})?-?[1-9]d{6,7}$/
雖然也能匹配上述目標字元串,但也會匹配(0551-88888888這樣的字元串。當然,這不是我們想要的。

其實這個正則也不是完美的,因為現實中,並不是每個3位數和4位數都是一個真實的區號。

這就

4. 將正則表達式(abc)*轉換為nfa,最多需要多少個狀態

5個:起始,a,b,c,結束。
從起始,a,b,c可以轉移到a,b,c,結束四個當中的任何一個。

閱讀全文

與正則表達式轉NFA代碼相關的資料

熱點內容
網路機頂盒移動網路 瀏覽:391
iphone手機百度雲怎麼保存到qq 瀏覽:148
資料庫設計與實踐讀後感 瀏覽:112
js對象是什麼 瀏覽:744
網頁文件存pdf 瀏覽:567
文件夾正裝 瀏覽:279
剛復制的文件找不到怎麼辦 瀏覽:724
試運行適用於哪些體系文件 瀏覽:987
ghost文件復制很慢 瀏覽:967
傑德原車導航升級 瀏覽:240
編程dest是什麼意思 瀏覽:935
linux埠鏡像 瀏覽:820
iphone5屏幕清塵 瀏覽:157
機頂盒密碼怎麼改 瀏覽:672
w7系統下載32位教程 瀏覽:618
pcb文件包括哪些內容 瀏覽:598
g00文件 瀏覽:607
用bat程序刪除程序 瀏覽:516
dnf鬼泣90版本打安圖恩 瀏覽:668
245倒角編程怎麼計算 瀏覽:599

友情鏈接