正則匹配問題(power8競賽敏感詞過濾)

這個賽事我是寫了一個,python單線程60秒左右,雖然不知道別人3秒是怎麼做的,但是論複雜度,這的方法已經是線性時間複雜度了,所以這裏寫個分享,供大家指正。

線性複雜度:這裏所說的線性複雜度指的是,只與需要匹配的文本線性相關,而與敏感詞的數量沒關係。如果你已經做到了這一點可以瞭解一下別人的方法,如果沒做到,也可以參考一下本文的方法。這一方法的主要特點是把所有敏感詞同時進行匹配,但是一開始的數據結構可能會有點麻煩。

數據結構部分:

散列索引Index:index是一65536的數組,全部初始化爲-1,對於所有敏感詞中的每一個通配符以外的字符我們把它存在數組char_array中,每個字符只存一次。對char_array中的每個字符取其Unicode編碼值(python中可用ord函數獲得),並在index中對應位置存儲其char_array中的位置,即index[ord(char_array[i])]=i;這樣敏感詞中每個字符A就有char_array[index[ord(A)]]=A。實現了散列功能,提升查找效率。

每個字符需要記錄的信息struct_C:記錄以下6個標記

a:這個字符是否爲某個敏感詞的第一個字,是爲1,否爲0;

b:這個字符是否爲某個敏感詞的最後一個字,是則記錄作爲結尾它是第幾個字的信息。(2,3,5,7,9,分別代表1、2、3、4、5;多種可能時相乘)

c:這個字符作爲第一個字時後面接的字符集合;

d:這個字符作爲第二個字時後面接的字符集合;

e:這個字符作爲第個字時後面接的字符集合

f:這個字符作爲第四個字時後面接的字符集合;(這裏把問題簡化一下不考慮更多情況了。)

爲了方便後面查看一個字符是否接在某個字符後面,給每個字符一個專屬的質數(素數)作爲標記,如只有“上學”“上課”“上班”三個詞時,可給出 (上:2,學:3,課:5,班:7)的對應表,這時“上”作爲第一個字時後面接的字符集合可表示爲 3X5X7 即 105;如果某個字符對應的素數a滿足 105%a=0則這個字符必定屬於後接字符集合中的一個。


以上部分都是對敏感詞的處理,其目的是把所有敏感詞合成一個整體,然後只進行一次匹配。


匹配過程:

對於一個字符串,從第一個字符開始查看其Unicode編碼所對應index位置中值是否爲-1;如果不爲-1;則檢查標記a是否爲1;然後繼續觀察後面的4個字符是否爲該字符的後接字符。就這樣每次只看兩個相鄰的有效字符能否連接起來。下面舉個例子說明:

假設只有“上.{0,3}學”(.{0,3}表示上課中間可以有0-3個任意字符),“上.{0,3}課”,“上.{0,3}班”,“訓.{0,3}練”四個正則所匹配的內容爲敏感內容;同上有(上:2,學:3,課:5,班:7,訓:11,練:13)的對應表。現在要對“下班後去上培訓課”字符串進行匹配。讀到“下”字時,index中對應的內容爲-1,不可能命中敏感內容;讀到“班”字時,index中記錄爲3(因爲班是第4個字);但是標記a爲0,不可能作爲敏感內容的第一個字;index對應內容爲-1,繼續跳過“後去”兩個字符;遇到“上”字時,發現其可以作爲敏感內容的開始,於是讀取上作爲第一個字的後接字符集105;”培“不是有效字符;”訓“字是有效字符,但是其專屬質數11不能被105整除(105=3*5*7,只有一種分解方式),繼續過;”課“字是有效字符,並且5能被105整除,檢查發現”課“剛好是一個敏感內容的結尾,並且剛好是第二個有效字,匹配通過”上培訓課“。


其他:

其實通過這種方法進行匹配,只能做到和原有的正則項”近似“,雖然不等價,但也是一個較好的近似。其中有很多細節處理都沒提及,不過本文的重點是線性時間複雜度:與需要匹配的敏感詞數量多少無關,只與原文本長度有關。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章