簡體   English   中英

轉換為狀態機的正則表達式的簡短示例?

[英]Short example of regular expression converted to a state machine?

在Stack Overflow播客#36( http://blog.stackoverflow.com/2009/01/podcast-36/ )中,有人表達了這樣的觀點:一旦你理解了設置狀態機是多么容易,你就會知道永遠不要試圖不恰當地使用正則表達式。

我做了很多搜索。 我發現了一些學術論文和其他復雜的例子,但我想找一個簡單的例子來幫助我理解這個過程。 我使用了很多正則表達式,我想確保我永遠不再使用“不恰當”。

當然,雖然你需要更復雜的例子來真正理解RE的工作原理。 考慮以下RE:

^[A-Za-z][A-Za-z0-9_]*$

這是一個典型的標識符(必須以alpha開頭,后面可以包含任意數量的字母數字和非字符字符,包括無字符)。 以下偽代碼顯示了如何使用有限狀態機完成此操作:

state = FIRSTCHAR
for char in all_chars_in(string):
    if state == FIRSTCHAR:
            if char is not in the set "A-Z" or "a-z":
                error "Invalid first character"
            state = SUBSEQUENTCHARS
            next char
    if state == SUBSEQUENTCHARS:
            if char is not in the set "A-Z" or "a-z" or "0-9" or "_":
                error "Invalid subsequent character"
            state = SUBSEQUENTCHARS
            next char

現在,正如我所說,這是一個非常簡單的例子。 它沒有說明如何進行貪婪/不一致的匹配,回溯,一行(而不是整行)的匹配以及RE語法容易處理的狀態機的其他更深奧的功能。

這就是REs如此強大的原因。 執行單線程RE可以執行的實際有限狀態機代碼通常非常長且復雜。

您可以做的最好的事情是獲取特定簡單語言的一些lex / yacc(或等效)代碼的副本,並查看它生成的代碼。 它並不漂亮(它不一定是因為它不應該由人類閱讀,它們應該是在查看lex / yacc代碼),但它可以讓你更好地了解它們是如何工作的。

一個相當方便的方法來幫助查看這個在任何模式上使用python的鮮為人知的re.DEBUG標志:

>>> re.compile(r'<([A-Z][A-Z0-9]*)\b[^>]*>(.*?)</\1>', re.DEBUG)
literal 60
subpattern 1
  in
    range (65, 90)
  max_repeat 0 65535
    in
      range (65, 90)
      range (48, 57)
at at_boundary
max_repeat 0 65535
  not_literal 62
literal 62
subpattern 2
  min_repeat 0 65535
    any None
literal 60
literal 47
groupref 1
literal 62

'literal'和'range'之后的數字是指它們應該匹配的ascii字符的整數值。

動起來做自己的!

HTTP://osteele.com/tools/reanimator/ ???

有限狀態機

這是一個非常好的拼湊工具,可以將正則表達式可視化為FSM。 它不支持您在現實世界正則表達式引擎中找到的某些語法,但肯定足以准確理解正在發生的事情。

問題是“如何選擇狀態和轉換條件?”或“如何在Foo中實現我的抽象狀態機?”

如何選擇狀態和轉換條件?

我通常使用FSM來解決相當簡單的問題並直觀地選擇它們。 我對另一個關於正則表達式的問題的回答中 ,我只是將解析問題看作是標記對Insideoutside的解析問題,並從那里寫出轉換(具有開始和結束狀態以保持實現清潔)。

如何在Foo中實現我的抽象狀態機?

如果您的實現語言支持cswitch語句之類的結構,那么您可以打開當前狀態並處理輸入,以查看接下來要執行的操作和/或轉換。

如果沒有類似switch的結構,或者如果它們在某種程度上存在缺陷,那么你if樣式分支。 啊。

寫在c中的一個地方我鏈接的例子看起來像這樣:

token_t token;
state_t state=BEGIN_STATE;
do {
   switch ( state.getValue() ) {
   case BEGIN_STATE;
      state=OUT_STATE;
      break;
   case OUT_STATE:
      switch ( token.getValue() ) {
         case CODE_TOKEN:
            state = IN_STATE;
            output(token.string());
            break;
         case NEWLINE_TOKEN;
            output("<break>");
            output(token.string());
            break;
         ...
      }
      break;
   ...
   }
} while (state != END_STATE);

這是相當混亂的,所以我通常將state案例分解為單獨的函數。

我確定有人有更好的例子,但是你可以查看Phil Haack的這篇文章 ,它有一個正則表達式的例子和一個狀態機做同樣的事情(還有一個帖子還有一些正則表達式例子在那里我認為..)

檢查該頁面上的“HenriFormatter”。

我不知道你已經閱讀過哪些學術論文,但理解如何實現有限狀態機真的並不難。 有一些有趣的數學,但想法實際上是非常微不足道的理解。 理解FSM的最簡單方法是通過輸入和輸出(實際上,這包括大部分正式定義,我將在此處不再描述)。 “狀態”實質上只是描述已經發生並且可以從某一點發生的一組輸入和輸出。

通過圖表最容易理解有限狀態機。 例如:

alt text http://img6.imageshack.us/img6/7571/mathfinitestatemachinedco3.gif

所有這一切都說明如果你開始處於某種狀態q0(旁邊有一個開始符號的那個)你可以去其他狀態。 每個州都是一個圓圈。 每個箭頭代表一個輸入或輸出(取決於你如何看待它)。 另一種考慮有限狀態機的方法是“有效”或“可接受”輸入。 某些輸出字符串不可能是某些有限狀態機; 這將允許您“匹配”表達式。

現在假設你從q0開始。 現在,如果您輸入0,您將進入狀態q1。 但是,如果您輸入1,您將進入狀態q2。 您可以通過輸入/輸出箭頭上方的符號查看此信息。

假設您從q0開始並獲得此輸入

0,1,0,1,1,1

這意味着你已經完成了狀態(沒有輸入q0,你只是從那里開始):

q0 - > q1 - > q0 - > q1 - > q0 - > q2 - > q3 - > q3

如果沒有意義,用手指追蹤圖片。 請注意,對於輸入0和1,q3都會返回自身。

說出這一切的另一種方式是“如果你處於狀態q0並且你看到0轉到q1,但如果你看到1轉到q2。” 如果您為每個州制定了這些條件,那么您幾乎完成了定義狀態機的工作。 所有你需要做的就是有一個狀態變量,然后是一個輸入輸入的方法,基本上就是那里。

好的,為什么這對喬爾的陳述很重要? 好吧,建立“一切正常的表達以統治所有”可能非常困難,也很難維持修改甚至其他人回來理解。 此外,在某些情況下,它更有效。

當然,狀態機還有許多其他用途。 希望這會有所幫助。 請注意,我並不打算進入理論,但有一些關於FSM的有趣證據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM