關於從普通文字提取正規表示式的再思考

2022-02-25 05:45:59 字數 2786 閱讀 7787

rex按:

文章之後,一直在考慮如何真正實現從普通文字中歸納正規表示式的實現。走了許多彎路,也學了不少知識。例如,perl黑豹書上覆雜的資料結構、匿名雜湊和陣列、refenrence;紫龍書上的狀態機的構造,資料結構上圖論的知識,都是很有用的。另外還新學了graphviz

的用法。以前覺得很神秘,不過一用才發現很直觀。本文的插圖是使用online版本的graphviz

畫的。這樣以詞為單位做完之後,再逐個字母地分隔開來,遞迴地處理(option1|option2…)的部分。先是單詞級,再是字母級,有利於先在最大程度上找出重複的內容;而且粗化和細化的處理過程,思路是一致的,粒度不同罷了。

新手請自重,高手請賜教,我的思路未必是正確或最優的。

問題

this is a red fox

this is a blue firefox

this is a pig

a red fox

請寫一則程式,根據文字內容,自動構造(比較合理的)正規表示式,使之能夠匹配檔案中每一行文字。

標準正則

有兩種極端的解法是不可取的:

^.*$

^(this is a red fox|this is a blue firefox|this is a pig|a red fox)$

第一種失之於太寬泛,第二種失之於太狹隘。太寬泛則泥沙俱下,無論什麼文字都能匹配;太狹隘則僵化死板,缺乏靈活性。好的正規表示式源於例文字(從例文字中提取規律),又高於例文字(能匹配同規律的其它文字)。匹配什麼,排除什麼,都有定則,所謂「君子有所為而有所不為」,指的就是這種情況(貌似跑題了:))。

那麼,如何是比較靠譜的正規表示式呢?以上文的例子而言,可以是:

^(this is )?a (red fox|blue firefox|pig)$

現在我們向著標準答案出發。

思路

任何複雜的電路圖,都可以拆分為三種簡單的關係:串聯,併聯,短路。正規表示式也同理。

既然是一條正則匹配所有的文字,那麼這條正則(記為$re)也應該匹配第一行文字。

第一行文字為this is a red fox。那麼,從^this is a red fox$應該是$re的乙個(真)子集。它的路徑為:「^」->this->is->a->red->fox->」$」。全部節點之間,是串聯關係,從左到右依次排列即可。

示意圖如下(可以點選看全尺寸圖,下同):

同理,第二行文字也應該是$re的子集。不過,由於已經存在了由^->this->is->a的路徑,到a時出現支路,a->blue->firefox->$;

將此路徑新增到示意圖上,得到:

顯而易見,這兩條並列的支路,始於a,終於$,可以使用|來並列之。

好了,我們總結一下規律:

並列:如果存在a->b->c,且同時存在a->d->c,則b與d之間是併聯關係。即出發點相同,結束點相同,且出發點與結束點之間各有乙個以上的節點。並列使用括號來表示,之間以|分隔。例如,對於a->b->c,a->d->c,則可以使用a(b|d)c來表示其正則關係。

再往下,this is a pig,同理,只需要在原圖基礎上新增a->pig->$的支路即可。此時圖示如下:

最後一條,a red fox。這條貌似複雜,但是只需在^->a之間新新增了一條路徑而已;a->red->fox->$之間原有路徑,可以繼續使用。此時,得到完整的示意圖如下:

此時,觀察可知,一種新的情況出現了。同時存在^->a,和「^」->this->is->a兩條路徑。想一下初中物理電路圖,我們可以將這種情況稱為「短路」,即,「^」->this->is->a這個線路的^、a兩個節點之間,新增了一條無障礙通道,它能無視this、is的存在,因此,讓this->is這條路徑成為可選項。再總結一下規律:

如果有a->b->…c->d的路徑,且有a->d的路徑,則稱a->d之間存在短路,此時,b->…->c可以用(b->…->c)?來表示(就是用括號來表示被短路的部分,問號表示短路之)。

頂點a,d之間,最多存在乙個短路關係。但是可以有1或更多條並列的關係存在。

好了,分析結束,得到這樣的正則式:

^(this is )?a (red fox|blue firefox|pig)$

這也就是為什麼上文要強調是乙個節點的緣故。

如果我們再精益求精的話,可以對red fox|blue firefox|pig這部分遞迴地進行上述分析過程,進而得到 (red |blue fire)fox|pig這樣的結果。

實現

思路有了,程式設計就簡單了。perl中,固然可以使用比較簡潔的hash表來表示鍊錶之間的關係:

例如:my $hash;

$$hash=」";

$$hash=」";

…但是,節點的增刪修改都是麻煩事。(我在hash迷宮中lost了很久才爬出來)

抽空補了一下有向圖的知識,覺得可以簡化問題如下。

上圖其實是乙個有向圖,只需記錄所有的頂點集合,路徑集合,再來求各路徑之間的關係;最後列印輸出,即是所求。

頂點集合為:

(^, this, is, a, red, fox, blue, firefox, pig, $);

通路關係集合為:

(^->this, this->is,…)

這兩個集合在讀取文字檔案行的時候可以一次性建立。不複雜。關鍵是關係的確立。

再次總結,如下:

這些條件、判斷,均可以細化為函式。具體的程式從略。

jmeter 正規表示式從響應文字提取資料

1.正規表示式 2.正則編寫方法 1.確定左右邊界 2.將要匹配的內容換成 貪婪匹配任意字元 已這個介面為例 提取到頁面中的水果蔬菜 肉禽蛋奶 冷熱素食。我們先對這個介面發起請求,再從響應文字找到想要的資料,確定文字的左右邊界 肉禽蛋奶 左邊界為標紅部分,右邊界為空格,0為隨機取資料,1表示全選 取...

jmeter 正規表示式提取

我們在做壓測時,經常會碰到需要上個介面的結果作為引數傳遞到下乙個介面,此時需要用到正規表示式提取功能。1 新增jmeter正規表示式提取器 在具體的request下新增jmeter正規表示式提取器 jmeter正規表示式在 後置處理器 下面 例1如下 引用名稱 tokenid 自己定義 模板 1 匹...

正規表示式提取時間

時間的各種格式都可以通過正規表示式來匹配,例如我們想精確匹配hh mm的時間,即包含小時和分鐘,可以使用下面的表示式 0 9 0 0 9 1 0 9 2 0 3 0 5 0 9 0 9 0 0 9 1 0 9 2 0 3 0 5 0 9 更多關於時間和日期的正規表示式,參考 regexlib.pub...