1. 程式人生 > >正則引擎入門——正則文法匹配可以簡單快捷(二)

正則引擎入門——正則文法匹配可以簡單快捷(二)

前言

正文

正則表示式

  正則表示式是一個用來表示一系列字元的字串的符號,當一個確定的字串處於一個正則表示式所描述的字串系列時,我們通常說這一正則表示式匹配了這一字串。
  最簡單的正則表示式是一個字面上的字元,除了一些特殊的元字元:*+?()| 以外,字元匹配的是它們自身。而為了匹配特殊的元字元,我們在這些元字元之前加上一個斜線 \ ,例如\+ 則可以匹配加號。
  兩個正則表示式相併聯或串聯可以形成新的正則表示式:如果e1可以匹配s,而e2匹配t,那麼e1|e2匹配s或者t,e1e2匹配st。
  元字元*,+,?代表重複操作符,e1*匹配一系列零個或多個元素的字串,其中的每一個元素均匹配e1

;e1+匹配一個或多個;e1?匹配零個或一個。
  操作符的優先順序,由弱到強排列,首先是並聯 |,之後是串聯,最後是重複操作符。括號可以用來改變結合的順序,就像書寫算術表示式一樣。例如:ab|cd與(ab)|(cd)含義相同,ab*與a(b*)含義相同。
  到目前為止我們所介紹的語法只是傳統的Unix egrep的正則表示式的語法的一個子集。而這個子集完全有能力去描述所有的正規文法(3型文法),不嚴謹的說,正規文法是一系列的可以通過一趟掃描並使用固定大小的記憶體容量進行匹配的字串。更新的正則引擎(特別是Perl以及與其相同的那些)加入了許多新的操作符和轉義字元。這些新的特性使得正則文法更加的簡潔而隱晦,但常常卻不是那樣的有用,這些奇特的正則表示式通常都需要更長的匹配時間。
  有一個常見的正則表示式的擴充套件的確為正則表示式提供了更加強大的功能——回溯引用(或反向引用)(backreferences).\1 \2之類的回溯符號會去匹配被該符號之前的括號中的正則表示式所匹配的字串,如(cat|dog)\1會匹配catcat和dogdog但不會匹配catdog或dogcat。從理論上說,帶有回溯引用功能的正則表示式不再是正規文法。回溯引用帶來強大功能的同時也需要付出巨大的代價:在最壞的情況下,一些知名的正則引擎需要耗費指數級的匹配時間,就如Perl所使用的那樣。毋庸置疑的,Perl不能移除回溯引用這一功能,但是當一個正則表示式中並沒有使用回溯引用時,Perl可以採用更加快速的演算法進行匹配,而這篇文章便是介紹這些更加快速的演算法的。

有限自動機

  另一種描述一類字串的方法是使用有限自動機。有限自動機同時也叫作狀態機,我們會交換使用自動機和狀態機這兩個詞。
  舉一個簡單的例子,下圖是正則表示式a(bb)+a的狀態轉換圖:
states change
  有限自動機在任意時刻只會處於其中的一個狀態上,這些狀態在上圖中使用圓圈表示,(圓圈中新增的字母只是為了討論方便,但他們並不是自動機的一部分。)自動機不斷地讀入字元,並根據這些字元改變自己的狀態。圖中的自動機有兩個特殊的狀態:初始狀態S0和結束狀態S4。初始狀態被一個單獨的箭頭所標註,結束狀態是雙層的圓圈。
  狀態機一次讀入一個字元,並通過箭頭的指向來更改自己的狀態。假設輸入的字串是abbbba。當狀態機讀入了第一個字元a的時候,它進入了初始狀態S0

,並通過a的箭頭來到了S1,狀態的轉換一直持續進行:讀入b進入S2,讀入b進入S3,讀入b進入S2,讀入b進入S3,最後讀入a進入S4
states change2
  狀態機最終在S4上結束,因此它匹配了這個字串。如果狀態機在非結束狀態上停止,那它就沒有匹配這一字串。如果狀態機在執行的時候,讀入了一個字元,但這一字元在圖中並沒有相應的箭頭指向下一狀態,那狀態機則會提前結束。
  在這之前我們討論的自動機叫做確定狀態自動機(DFA),因為在任意的狀態下,任何可能的一個輸入均只會讓自動機進入最多一個新的狀態。我們同樣可以創造一個需要在多個可能的下一狀態中進行選擇的自動機。例如,下圖中的自動機與前文所說的自動機等價,但是卻不是“確定”的。
NFA image
  上圖中的自動機是非確定的因為當它在狀態S2時讀入了一個b,那它便有了多個可能的下一狀態,它可以回到S1,並認為接下來讀入的是兩個b,或者它可以來到S3並認為下一個輸入是a。因為自動機無法提前檢視字串中剩下的輸入,因此它沒有辦法知道哪一個才是正確的決定。這樣的自動機被叫做不確定狀態自動機(NFA)。一個NFA匹配一個字串如果它能在讀入該字串後通過箭頭到達匹配狀態。
  有時候讓NFA帶有無字元的箭頭是非常方便的,我們會保留這些沒有標誌的箭頭,一個NFA可以在任何時候,在沒有讀入任何字元的狀態下選擇通過沒有標誌的箭頭來到下一個狀態。下圖中的NFA與上圖中的NFA等價,但是空的箭頭使a(bb)+a的表示更為清晰。
NFA image2

將正則表示式轉換為NFA

  正則表示式與NFA的能力是相互等價的,每一個正則表示式都有與其相對應的NFA(它們匹配相同的字串),反之亦然。(DFA的能力與NFA,正則表示式也是等價的)有多種方法可以將正則表示式轉換為NFA。接下來介紹的方法由Thompson於1968年在他的CACM文章中首次提出。
  一個正則表示式的NFA從該表示式的子表示式開始,通過為每一個操作符建立相應的NFA而建立起來。NFA的基本部分不包含結束狀態,而這些基本部分有一個或多個懸空的箭頭,不指向任何狀態。構建NFA的程式會在結束之前將這些懸空的箭頭指向結束狀態。
  匹配單個字元的NFA如下:
NFA image3
  e1e2的NFA將e1最後的箭頭與e2的開始相連線:
NFA image4
  e1|e2的NFA增加了一個新的開始狀態指向e1或者e2
NFA image5
  e?的NFA將e與一個空的箭頭以或的方式連線:
NFA image6
  e*的NFA使用同樣的或的形式但是將e最後的箭頭與開始狀態連線起來:
NFA image7
  e+的NFA同樣有一個環,但是要求至少通過e一次:
NFA image8
  數一數上圖中的新的狀態的數量,我們可以知道這種構造方法為每一個字元或者元字元增加了一個狀態,除了括號以外。因此最後構造出的NFA的狀態數量不會超過原始的正則表示式的長度。
  正如我們之前討論過的例子中的NFA一樣,我們完全可以將NFA中的空箭頭去掉,我們也可以在一開始構造的時候就避免使用空箭頭。但使用空箭頭可以使NFA閱讀起來更容易,同時在使用C實現時也更加的簡單,所以我們會保留它們。

相關推薦

引擎入門——文法匹配可以簡單快捷()

前言 正文 正則表示式   正則表示式是一個用來表示一系列字元的字串的符號,當一個確定的字串處於一個正則表示式所描述的字串系列時,我們通常說這一正則表示式匹配了這一字串。   最簡單的正則表示式是一個字面上的字元,除了一些特殊的元字元:*+?

引擎入門——基於虛擬機器的匹配(三)

前言 正文 Pike實現   在“執行緒化”的實現,如thompsonvm中,我們簡單地將儲存後的指標加入到執行緒的狀態中。Rob Pike首先於文字編輯器sam中使用了這種實現方式。 struct Thread { Inst

引擎入門——基於虛擬機器的匹配(一)

前言 正文 介紹   說出幾個如今被廣泛應用的位元組碼直譯器或者虛擬機器:Sun公司的JVM?Adobe公司的Flash?.NET或者Mono?Perl?Python?PHP?這些的確都很流行,但是還有一個比上述這些加起來都還要廣泛使用的,那便

表達式【範圍性匹配

bsp com pre www. find compile 轉義 什麽 sna 1、 import re key = r"<html><body><h1>hello world<h1></body></ht

C#表達式的遞歸匹配分析

重復字符 renren href ffffff share lock src www. net 在C#程序設計中經常會遇到這樣的需求,要求匹配出成對的小括號裏的內容,但是一般正則表達式中的 ?R 的語法似乎在C#中不被支持, 經過一番查找與測試,終於找到以下一段描述 /

介紹,創建、匹配Regex對象

查找字符串 環境 文本 hone 橫線 defined 例如 交互 python使用 1 前面的電話號碼查找程序能工作,但是 使用了很多代碼,做的事情卻有限; isPhoneNumber()函數有17行,但只能查找一種電話號碼模式。像415.555.4242或者(415)

http://www.cnblogs.com/chenmeng0818/p/6370819.html js中的表示式入門

http://www.cnblogs.com/chenmeng0818/p/6370819.html js中的正則表示式入門   什麼是正則表示式呢? 正則表示式(regular expression)描述了一種字串匹配的模式,可以用來檢查一個字串是否含有某

基礎表示式-入門

開發之路,羊腸九曲,荊棘密佈,幸得高人指點,前輩填坑,一路謹小慎微,終得工程圓滿;其間填坑之經驗,開路之歷程,皆為精華,不可棄之;記錄於此,以便事後回顧,亦想於有相關開發疑惑之同學做參考之用,文中如若有錯,懇請雅正,不勝感激。 基本的正則表示式 在使用正則表示式的時

Python表示式入門進階

1.1 正則表示式處理字串主要有四大功能1.匹配 檢視一個字串是否符合正則表示式的語法,一般返回true或者false2.獲取 正則表示式來提取字串中符合要求的文字3.替換 查詢字串中符合正則表示式的文字,並用相應的字串替換4.分割 使用正則表示式對字串進行分割。 1.2 Python中re模組使用正則表示

1.表示式-入門

    前言:今天先分享正則表示式的基礎元字元,後續會分享正則表示式的子表示式,回溯引用,前後查詢,嵌入條件,,全部分享完成之後,會嘗試著去分享一些例子與拆分介紹。如果文字描述有問題可以評論指出,如果概念很模糊,可以加我微信,我會盡量解答你的疑惑。 一 正則表示式的定義 正則表示式,

C#表示式入門(下)

一、匹配郵政編碼,郵政編碼為6位數字組成。 string code; code = Console.ReadLine(); Regex reg = new Regex(@"^\d{6}$",RegexOptions.None); Console.WriteLine(reg.IsMat

C#表示式入門(中)

一、忽略匹配優先模式 *? 重複任意次,但儘可能少重複 +? 重複1次或更多次,但儘可能少重複 ?? 重複0次或1次,但儘可能少重複 {n,m}? 重複n到m次,但儘可能少重複 {n,}? 重複n次以上,但儘可能少重複   【例二】在滿足匹配時

C#表示式入門(上)

一、說明 使用正則表示式 需要包含名字空間using System.Text.RegularExpressions; .Net使用的是傳統型NFA引擎,.NET正則表示式流派概述 分類 舉例 字元縮略表示法

Python 表示式入門

引子 首先說 正則表示式是什麼? 正則表示式,又稱正規表示式、正規表示法、正規表示式、規則表示式、常規表示法(英語:Regular Expression,在程式碼中常簡寫為regex、regexp或RE),電腦科學的一個概念。正則表示式使用單個字串來描述、匹配一系列匹配某個句法

表示式入門到掌握

如何使用本教程 最重要的是——請給我30分鐘,如果你沒有使用正則表示式的經驗,請不要試圖在30秒內入門——除非你是超人 :) 別被下面那些複雜的表示式嚇倒,只要跟著我一步一步來,你會發現正則表示式其實並沒有你想像中的那麼困難。當然,如果你看完了這篇教程之後,發現自己明白了很多,卻又幾乎什麼都記不

grok表示式一行多個結果匹配

原理介紹 grok內建了一些常用正則的表示式,其在grok-pattern檔案中; 你可以自己定義一些喜歡的正則表示式,用於匹配自己需求的內容: 例如:中國式的時間匹配2018/9/11 9:46:32  TIMESTAMP_CHS %{YEAR}/%{MO

五年開發經驗告訴你什麼是Java表示式入門

一:什麼是正則表示式 1.定義: 正則表示式是一種可以用於模式匹配和替換的規範,一個正則表示式就是由普通的字元(例如字元a到z)以及特殊字元(元字元)組成的文字模式,它 用以描述在查詢文字主體時待匹配的一個或多個字串。正則表示式作為一個模板,將某個字元模式與所搜尋的字串進行匹配。 2

快速入門表示式”

導讀   像大多數的數學表示式一樣,正則表示式也是一箇中很“反人性”的表示式,相信很多人看正則表示式跟看天書一樣,即使學習和使用過正則表示式,也很快就忘了它的規則。而本文的目的就是讓普通人能夠輕鬆快速地瞭解正則表示式,並把握正則表示式的設計哲學,不會那麼容易就

表示式 入門

檢索文字檔案:Egrep 文字檢索是正則表示式最簡單的應用之一 ——許多文字編輯器和文書處理軟體都提供了正則表示式檢索功能。最簡單的就是egrep。在指定了正則表示式和需要檢索的檔案之後,egrep會嘗試用正則表示式來匹配每個檔案的每一行,並顯示能夠匹配的行。 Egrep元字元 行的起始

Python3 表示式中group()方法獲得匹配結果

正則表示式中用match()方法可以獲得匹配的字串內容。 如果想從字串中提取出一部分內容,可以用括號將提取目標括起來。 括號()實際上標記了一個子表示式的開始和結束的位置,被標記的每個子表示式會依次對應每個分組,呼叫group()方法傳入分組的索引即可獲得提取的結果。