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進行

 

源碼:

https://github.com/biaoJM/Simple-RegExp-C


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM