C語言實現簡化的正則表示式
語法:
- 正則表示式和待匹配字串都是一行
- “^” 標記正則表示式的開始
- “$” 標記正則表示式的結束
- “*” 匹配前面的子表示式零次或多次
- “+” 匹配前面的子表示式一次或多次
- “?” 匹配前面的子表示式零次或一次, 當該字元緊跟在任何一個其他限制符(*,+,?,{n},{n,},{n,m})後面時,表示該匹配模式是非貪婪的,而不是匹配前面的子表示式
- “{n}” n是一個非負整數。匹配確定的n次
- “{n,}” n是一個非負整數。至少匹配n次
- “{n,m}” m和n均為非負整數,其中n<=m。最少匹配n次且最多匹配m次
- “.” 匹配除“\n”之外的任何單個字元
- “x|y” 匹配x或y,其中x和y是兩個子表示式,如果是字元就是單個字元
- “[xyz]”字符合集,匹配其中的任意一個字元,如果兩個字元之間有”-”,就表示這三個字元用於匹配一個ASSIC碼值在兩字元之間的一個字元,如果開頭有”^”,表示負值字元集合。匹配未包含的任意字元
- “(pattern)”一個子表示式,可巢狀
- \b匹配一個單詞邊界,即是否後面是非識別符號字元,只是檢測,不匹配實際內容
- \B匹配非單詞邊界,即是否後面不是非識別符號字元,只是檢測,不匹配實際內容
- \d 匹配一個數字字元。等價於[0-9]。
- \D 匹配一個非數字字元。等價於[^0-9]。
- \f 匹配一個換頁符。等價於\x0c
- \n 匹配一個換行符。等價於\x0a
- \r 匹配一個回車符。等價於\x0d
- \s 匹配任何空白字元,包括空格、製表符、換頁符等等。等價於[ \f\n\r\t\v]。
- \S 匹配任何非空白字元。等價於[^ \f\n\r\t\v]。
- \t 匹配一個製表符。等價於\x09
- \v 匹配一個垂直製表符。等價於\x0b
- \w 匹配包括下劃線的任何單詞字元。等價於“[A-Za-z0-9_]”。
- \W 匹配任何非單詞字元。等價於“[^A-Za-z0-9_]”。
- \xn匹配n,其中n為十六進位制轉義值。十六進位制轉義值必須為確定的兩個數字長。例如,“\x41”匹配“A”。“\x041”則等價於“\x04&1”。正則表示式中可以使用ASCII編碼。.
- \num匹配num,其中num是一個正整數。對所獲取的匹配的引用。例如,“(.)\1”匹配兩
- 個連續的相同字元。只支援0≤num≤9,並且引用的只能是元表示式,比如(ab)將計數為兩個表示式”a”和”b”而忽略括號
策略:
先將正則表示式解析,生成一棵語法樹,樹枝是”()”“[]”“|”帶來的子表示式,節點的exp_id表示這個節點將用於匹配怎樣的字元,還有欄位記錄這個表示式將重複的次數。
“()”的子樹是和主樹的結構一樣的,解析規則也是相同的,但是”[]”和”|”的子樹有自己的解析規則
每棵子樹的根節點不匹配實際內容,而是用於指示它有子樹
再用這棵語法樹對字串進行匹配
Step1:解析語法樹
每個函式都只進行一個或特定幾個字元的解析,之後遞迴的呼叫以遞迴下降分析
Check:
首先判斷是否達到了正則表示式尾
“|”會再當前節點之前插入一個節點,並將當前節點移到插入的節點的孩子上,因為難以只對之後的一個表示式進行特殊處理,所以之後將繼續解析。而是在解析完成之後進行再次的處理,遇到”|”的表示式的時候會將其後面的一個表示式放到其孩子樹(此時已有一個節點)的後面,這樣孩子樹將有兩個節點
“-”會判斷當前的模式,如果在一箇中括號中,並且當前節點和後面的都是一個非轉義字元,那麼就修改當前的節點為字元範圍匹配,即便後面的是反斜槓也可以判斷是否是非轉義字元
“+”“*”會直接修改當前節點的重複次數(即便它有一棵孩子樹)
“?”需要判斷當前的節點是否已經被限制符修飾過了,如果是就將當前節點設定為非貪婪的,否則就只修改重複次數
在遇到”(““{““[““\”時會進入相應的函式進行特定的解析
遞迴呼叫自己進行遞迴下降解析
Check “\”:
\x將會有一個輔助函式將其後的兩個字元解析為十進位制整數,並插入為char
\+數字,將會有一個函式尋找對應位置的表示式指標,因為找的只是元表示式,所以不會有孩子節點,而且因為表示式只會被使用而不會被改變,所以引用也可以直接複製,不用深複製
Check”(“:
因為用了全域性變數儲存表示式樹的頭節點和當前節點,所以只用備份當前的值,並將值設定為新節點的孩子節點,之後再呼叫check就可以為新節點的孩子節點生成一個子樹
Check”[“:
會和”()”進行相同的操作,差異是呼叫時指定的模式,而且”[]”再開頭會判斷是否有”^”
Check”{}”:
識別模式並修改當前的節點重複次數
Step2:檢查字串
Match pattern將會遍歷表示式連結串列,並呼叫match expression檢查每個單獨的表示式。子樹的遍歷將會在match expression中通過呼叫match pattern進行