最初步的正規表示式引擎 生成nfa

2022-03-15 18:58:15 字數 3633 閱讀 5912

這個版本修改了前面版本的兩個個bug。

第乙個:識別到字符集的時候,只是將name_number加1,卻並不對reg_pattern_table[name_number]進行初始化。

第二個:識別到假名的時候,並不為他分配乙個name_number,而只是在hash表中為其分配乙個表項。

現在,當識別到這兩個的時候,都會為之分配乙個name_number,並在reg_pattern_table中正確的初始化。

相關的修改的**都在tackle_particle()函式中。

還有對tackle_cat()函式的定義移動到了tackle_invisible_cat()函式的前面。

另外乙個重大的修改就是,將當前檔案分割為多檔案了,原來的正則處理部分劃分為reg_preprocess.h。

而新的nfa生成部分為nfa_preocess.h。

nfa_process.h基本生成了nfa,但不是按照教科書進行的,具體方法可以看**,待會我會寫一篇文章來講我的方法。

1 #include "

regular_preprocess.h"2

//這個版本終於要上nfa了,好興奮啊3//

由於連個節點之間可能有多條邊,所以只能用鄰接表來儲存了4//

注意這裡是有向圖5//

對於每乙個token,這裡都會生成乙個或多個圖節點6//

但是每個token會附帶另外的兩個域,即這個token的開始節點和結束節點7//

因為內部節點對於外部來說是不可連線的,所以不需要暴露8//

這裡有乙個難題,就是空轉換如何表示,這裡我們必須找乙個不可列印字元來代表空轉換9//

樓主自己查了一下asc碼表,選擇了17號字元,因為

10//

鬼才知道那個字元啥意思,而且看描述c語言裡面也不會出現這個字元吧,

11//

我看了看鍵盤,非常欣慰,因為我不知道怎麼打出17號字元

12//

好,就選它了。

13//

對於nfa圖,這裡維護了乙個圖節點的陣列,而這個陣列組成了鄰接表

14 typedef struct

_graph_edge_list

15graph_edge_list,*p_edge_list;

20 typedef struct _node_for_token//

對於每乙個token,我們記錄他的進入節點和終止節點,為了連線成大的nfa圖用

21node_for_token,pnode_for_token;

25 node_for_token token_node[100

];26

//每乙個token對應乙個節點,所以100就夠了,當然現在處理的是小的輸入

27//

注意這裡有乙個特殊的地方,對於括號運算子,他的內容與他的子節點的內容是一樣的

28//

而對於假名操作符,他的內容與他的子節點的內容也是一樣的,但是他的內容永遠都不會被其他節點所利用

29//

因為在生成token的過程中,入棧的是他所代表的子節點,所以他的token是不會被其他的token所引用的

30//

還有乙個最需要注意的地方,就是每乙個token都有其相對應的token_node,而且這兩者的索引都相同

31//

這個設定便利了nfa的處理,同時也就造就了上面說的括號與中括號的特殊性

32int token_node_number=1;//

這裡是用來遍歷整個token表的,每增加1,則token_node的內容增加1

33 p_edge_list nfa_node[400];//

因為生成nfa的過程中可能生成四倍於輸入的節點,所以定為這麼大

34int nfa_node_number=0;//

這個是nfa中的節點的標號

35void add_edge(int nfa_node_begin,int nfa_node_end,char label)//

新增邊的函式

3643

void generate_nfa_node(void)44

149 token_node_number++;

150break

;151

case

maybe_exist:

152//

處理問號運算子,其實這個就比較簡單了,只需要在子表示式的頭節點與尾節點之間加一條空邊

153 reg_pattern_origin=reg_pattern_table[token_node_number].sub;

154 add_edge_from=token_node[reg_pattern_origin].begin;

155 add_edge_to=token_node[reg_pattern_origin].end;

156 add_edge(add_edge_from,add_edge_to,(char)17

);157 token_node_number++;

158break

;159

case

one_or_more:

160//

這種情況下,我另外建立乙個節點當作本token的尾節點

161//

然後新增兩條空邊,起點都是子節點的尾節點,終點乙個是子節點的開始節點

162//

另外乙個就是當前節點的尾節點

163 nfa_node_number++;

164//

這個節點是作為當前節點的尾節點

165 nfa_node[nfa_node_number]=null;

166 token_node[token_node_number].end=nfa_node_number;

167 add_edge_to=nfa_node_number;

168 reg_pattern_origin=reg_pattern_table[token_node_number].sub;

169 add_edge_from=token_node[reg_pattern_origin].end;

170 add_edge(add_edge_from,add_edge_to,(char)17

);171 add_edge_to=token_node[reg_pattern_origin].begin;

172 add_edge(add_edge_from,add_edge_to,(char)17

);173 token_node_number++;

174break

;175

default

:176 printf("

a type can't be recognised, please check\n");

177 token_node_number++;

178break

;179

}180

}181 }

最初步的正規表示式引擎

這裡只是當作自己的 版本管理器使用,並不去詳細介紹 畢竟我的注釋裡面已經說明了很多。注意,當前的假定是輸入自己不能有錯誤,而且 這幾個操作符是保留字,其他的字元則當作其自身意思。當前不考慮轉義字元及三元組,以及不考慮子表示式命名,因此只能處理乙個長正規表示式。1 include 2 include ...

正規表示式初步

正規表示式是乙個特殊的字串行,它能幫助你方便的檢查乙個字串是否與某種模式匹配,python 自1.5版本起增加了re 模組,它提供 perl 風格的正規表示式模式。compile 函式根據乙個模式字串和可選的標誌引數生成乙個正規表示式物件。該物件擁有一系列方法用於正規表示式匹配和替換。1 基本常用的...

MySQL正規表示式初步

你還可以學習 mysql學習精粹 我們知道,在sql之中,可以用 like 這個謂詞 表示式 來進行模糊檢索,並支援 等佔位符.但是,這個模糊檢索的功能有很多限制,簡單來說就是太模糊了。在mysql中提供了 regexp 關鍵字來支援正規表示式,當然,只是一些很簡單的正則啦。首先,我們構造一些測試資...