采用棧解析包含&|()的關(guān)鍵詞規(guī)則表達式

1. 需求

例如用戶給定一個包含與或關(guān)系的關(guān)鍵詞匹配規(guī)則:

(G20&中國&(互聯(lián)網(wǎng)|人工智能|AI)&(騰訊|阿里|阿里巴巴|百度|京東))

需要基于這個規(guī)則采集相關(guān)信息,此時就需要將該規(guī)則解析,看包含哪些詞,再根據(jù)這些詞去采集,需要解析成如下形式才能方便采集:

G20 中國 互聯(lián)網(wǎng) 騰訊
G20 中國 人工智能 騰訊
G20 中國 AI 騰訊
G20 中國 互聯(lián)網(wǎng) 阿里
G20 中國 人工智能 阿里
G20 中國 AI 阿里
G20 中國 互聯(lián)網(wǎng) 阿里巴巴
G20 中國 人工智能 阿里巴巴
G20 中國 AI 阿里巴巴
G20 中國 互聯(lián)網(wǎng) 百度
G20 中國 人工智能 百度
G20 中國 AI 百度
G20 中國 互聯(lián)網(wǎng) 京東
G20 中國 人工智能 京東
G20 中國 AI 京東

行與行之間是或的關(guān)系,行中每個詞之間是并的關(guān)系。

2. 解決方案

考慮到這種規(guī)則表達式類似于算術(shù)表達式,因此我們可以基于算術(shù)表達式對該規(guī)則進行解析:
與算術(shù)表達式類似,我們可以采用兩個棧:

棧1: 存儲規(guī)則符號如(&,|,())
棧2:存儲中間的詞,如中國,互聯(lián)網(wǎng)

這里不用像算術(shù)表達式計算那樣要考慮各種運算符的優(yōu)先級,只需要每次遇到右括號時,將棧1的規(guī)則符號彈出,直到彈出左括號,同時棧2需要彈出左右括號之間相應(yīng)的詞,再根據(jù)彈出的符號是與還是或的關(guān)系,拼裝彈出的詞,為新的詞序列,寫入棧2中。
直到規(guī)則表達式遍歷完且棧1為空,棧2長度為1時,返回棧2元素。

這里需要注意的是,遍歷規(guī)則表達式是以字符為級別,棧2中壓入的元素是以詞為序列的,詞與詞分割的標(biāo)準(zhǔn)即規(guī)則符號(&,|,())

偽代碼:
最終結(jié)果格式為:或之間的詞用#隔開,與之間的詞用空格隔開,如上面例子中的結(jié)果應(yīng)該為:

G20 中國 互聯(lián)網(wǎng) 騰訊#G20 中國 人工智能 騰訊#G20 中國 AI 騰訊#G20 中國 互聯(lián)網(wǎng) 阿里#G20 中國 人工智能 阿里#G20 中國 AI 阿里#G20 中國 互聯(lián)網(wǎng) 阿里巴巴#G20 中國 人工智能 阿里巴巴#G20 中國 AI 阿里巴巴#G20 中國 互聯(lián)網(wǎng) 百度#G20 中國 人工智能 百度#G20 中國 AI 百度#G20 中國 互聯(lián)網(wǎng) 京東#G20 中國 人工智能 京東#G20 中國 AI 京東

stack1 = new Stack() //存儲規(guī)則符號
stack2 = new Stack() //存儲詞
word= ""http:// 記錄一個詞
for(char c <- inputString) ://遍歷輸入序列
    if(c 是規(guī)則符號&|()):
        if(words長度大于0):
            stack2.push(word);  //將詞壓入棧2
        if(c 是  [&|(]中的任一個):
            stack1.push(c)//壓入棧1
        if(c是右括號):
            list[] list;//記錄此刻彈出的所有詞
             while(stack1.size > 0 && stack1.pop != '(') ://彈出規(guī)則符號直到左括號
                  stack1.pop();
                  list.add(stack2.pop());
             list.add(stack2.pop)
             computeres = computKwsByAndOr(list,'&');
            stack2.push(computeres);//拼裝結(jié)果壓入棧2;
    else(c不是規(guī)則符號,即某個詞的字)://此時需要等到下一個規(guī)則符號時才能組裝成一個詞   
         word += c //將該字符拼接到上一個字的后面 
if(stack1為空 并且stack2只剩一個元素): return reverseString(stack2.pop());
if(stack1有多個元素,且都是一樣的規(guī)則符號(&|),并且stack2不為空):
      c1 = stack1.pop();
      list = stack2.pop();//彈出stack2的全部元素組成列表;
      res = computKwsByAndOr(list,c1);
      return reverseString(res);

def computKwsByAndOr(list[] , char c)://拼裝彈出的詞為結(jié)果格式
     res = ""
     temp = ""
     if(c是&):
          for(kw <- list):
              l = kw.split('#')//找出詞中或的關(guān)系,這樣要一一的和下一個詞與,
                               //例如list中其中兩個元素是:G20 中國 人工智能#G20 中國 AI
                            //另一個元素是騰訊,
                        //這兩個詞序列之間是與的關(guān)系,
                  //要合并成G20 中國 人工智能 騰訊#G20 中國 AI 騰訊
              for(kw_s <- l):
                    b = res.split('#')
                        for(kw_s_inner <- b):
                              temp += kw_s+" " + kw_s_inner + '#'
              res = temp;
      else if (c是|):
             res = String.join(list,'#')
      return res;

//由于基于棧是后進先出的,因此最終順序會與人們自己算出的順序不符
//例如(G20&中國&(互聯(lián)網(wǎng)|人工智能))
//上面得到的結(jié)果是人工智能 中國 G20#互聯(lián)網(wǎng) 中國 G20
//為了方便用戶校驗解析結(jié)果,可以將#隔開的或關(guān)系詞組逆序,并且并之間的關(guān)系也逆序:
//即G20 中國 互聯(lián)網(wǎng)#G20 中國 人工智能
def reverseString(String data):
      string[] str = data.split('#');//先用#分割
      list;
      for(s <- str) :
           string[] inner_str = s.split(' ');//再用空格分割
           if(inner_str.length > 1) :
                string str_append;
                for(i:inner_str.length-1->0): //逆序拼接
                      str_append += inner_str[i]+' '
                list.add(str_append);
  list.reverse();
return list.join('#');
            
          

3.具體代碼

具體代碼實現(xiàn)參照GitHub
https://github.com/qmh2014/keywordsExtract

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,619評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,155評論 3 425
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,635評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,539評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,255評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,646評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,655評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,838評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,399評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,146評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,338評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,893評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,565評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,983評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,257評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,059評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,296評論 2 376