本文參考了:java
這是《計算理論101》系列的第一篇,將從最基本的有限狀態機講起。主要參考的課程和書籍有: Introduction to the Theory of Computation 3rd Edition 和 【Stonehill college CS】Introduction to the Theory of Computation 。git
如 Stonehill college 的 Professor of Computer Science Shai Simonson所說,這多是計算機課程中最抽象的一門了,但倒是任何 computer scientist(我以爲能夠延生至任何真正熱愛 CS 的人)至少須要瞭解的一門課。這門課不會教你如何寫代碼,也不會教你如何作一個計算機,而是着重於『計算機科學』中的『科學』兩個字,去了解計算機科學發展幾十年來前人閃耀的思想。程序員
還有一點,我認爲也是很重要的,那就是學習新知識那份最單純的快樂。github
好了,廢話很少說,開始正題~正則表達式
以一個程序員的角度,個人理解就是內存有限的一個機器,上面定義了一些函數,能夠從一個狀態跳轉到另外一個狀態。嚴格的數學定義,一個有限狀態機能夠定義爲一個五元組,以下圖表示(來源於Introduction to the Theory of Computation 3rd Edition P35):算法
能夠用圖直觀地表示:下圖這個狀態機,圓圈表示的是可能出現的狀態,可能輸入的值爲0和1,裝換函數就是那些箭頭,開始狀態爲 q1,accept 狀態爲 q2(用雙圓圈表示)。編程
一個有限狀態機的定義其實就是這麼簡單。微信
有限狀態機一個最顯然的特色就是內存有限,沒法記憶全部的歷史輸入,因此它可以解決的問題是有限的。至於什麼問題可以解決,什麼不能,後面再說。先來看看有限狀態機的應用。函數
這是《Introduction to the Theory of Computation 3rd Edition》書中提到的一個例子。gitlab
下圖中,門口和門背各有一個感應器(front 爲門口,rear 爲門背)。門的控制開關一共有兩個狀態:OPEN 和 CLOSED,輸入一共有四種狀況:FRONT(門口有人)、REAR(門背有人)、BOTH(門口門背都有人)、NEITHER(兩邊都沒人)。
有一個圖表示狀態轉換過程爲:
稍微解釋一下:
我對於這個門的設計表示懷疑,處於 CLOSED 狀態時,難道 REAR PAD 檢測到人不該該變成 OPEN 狀態嗎?也許是我哪裏理解得不對,有童鞋知道的歡迎指出。不過這一點不影響咱們對於有限自動機的理解。
這個自動門其實就能夠看做是一個最簡單的計算機了,它只有一個 bit 的存儲空間,能夠記錄當前門的狀態是OPEN 仍是 CLOSED。相似的還有電梯, 飲料機 等等。
事實上,最開始咱們骨灰級的程序員(計算機科學家)們,面對的就是相似的狀況,存儲空間極其有限。如今的不少嵌入式設備,內存一樣很是有限,因此有限狀態機仍是有用武之地的。
這裏推薦一個網站: regexper.com/ ,可以很是直觀地將正則表達式還原爲一個 finite state machine。另外開源地址以下: gitlab.com/javallone/r… 。
舉幾個正則表達式例子:
匹配手機號:/^1(3|4|5|7|8)\d{9}$/
:
匹配郵箱:^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$
匹配 IP 地址:^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
這裏不深刻代碼層,否則這篇文章就講不完了。有興趣的童鞋本身 Google 一下,後面有機會可能會再次講到。
這個 stackexchange 的連接裏面提到了不少: softwareengineering.stackexchange.com/questions/4…
設計一個FSM,可以識別被3整除的二進制字符串。好比accept 1001
,reject 1101
。 首先,咱們能夠把全部餘數(reminder)的可能性看成狀態,也就是三個狀態:0,1,2,其中0時 accept 狀態。 而後分析一下狀態轉換是怎麼樣的?二進制數,末位添加一個0表示乘以2,末位加1表示乘以2再加1,對於餘數,一樣是乘2或者乘2加1,只不過餘數會『進位』。
這樣就作完了,一個用普通算法很難解決的問題,用FSM是否是很簡單?會設計識別能被3整除的 FSM,接下來被四、五、六、七、8整除的是否是也會了?這裏,被2^k(k=1,2,3,4)整除還有一個更簡單的方法:轉換爲判斷末位至少有k 個0。
動手來畫一畫:
設計一個 FSM,可以識別 能被4整除的二進制字符串(末尾至少有兩個0)。 這裏把狀態設計爲目前爲止末尾收到了幾個0,一共有三個狀態:0個0,1個0,2個0。
有這個還能夠推廣到模式字符串識別,好比要識別特定子字符串 ,請看下面這個例子。
設計一個 FSM,可以識別子字符串abcab
。
爲了簡單起見,這裏把圓圈省略掉了,同時把中間的某些節點的狀態轉換忽略掉了。
狀態機的定義很是簡潔,可是功能很強大,並且很是有意思不是嗎?
碼字很辛苦,圖文並茂更辛苦,點個贊鼓勵一下~
廣告時間,歡迎你們關注個人微信公衆號。同時本文同步於 github: github.com/liaochangji…