1. 程式人生 > >正則表示式中常用符號

正則表示式中常用符號

一:

正則在Perl、Py森、Ruby、Java等語言中文字的正則表示式幾乎是一樣的

以前常用到的在網上都有現成的例子拿來用,比如電話格式、郵箱格式之類的。

但是自然語言處理中往往會根據自己的需求來制定一個表示式,如果正則的知識掌握的比較片面,在編寫自然語言處理程式時可能會覺得苦惱。

在《自然語言處理簡明教程》裡面有很系統的正則表示式教程,特意總結出來消化吸收。

二:

  • 雙斜線“//”

    最簡單的正則表示式就是這樣的,由類似於/hello world /的正則來搜尋語料庫中包含子字串“hello world”的任何字串相匹配。/e/是可以匹配到字串hello的。

  • 中括號“[]”

    []會匹配其中的某一個字元。比如現在有嫌疑人,我們只知道他的名字可能是下面三種的某一種,分別是張偉、李偉或者黃偉。就可以使用/[張李黃]偉/來在人口資料庫中匹配。

正則

匹配

模式例子

/[hH]/ello/

/[abc]/

/[1234567890]/

hello or Hello

‘a’或者’b’或者’c’

數字

“Hello!”

“happy~”

“1993年”

  • {}表示限制長度。如:.{1}表示匹配一個任意字元 
  • 連字元“-”

    用來劃定範圍,表示某一範圍內的任何字元。比如上個例子裡面的/[1234567890]/是不是感覺很不方便。如果表示為/[0-9]/就會顯得精簡的多。

正則

匹配

模式例子

/[A-Z]/

/[a-z]/

/[0-9]/

大寫字母

小寫字母

數字

“Hello!”

“happy~”

“1993年”

  • 脫字元“^”

    如果在方括號之後有脫字元“^”,對應的模式就是否定的。

正則

匹配

模式例子

/[^A-Z]/

/[^aA]/

/[0-9]/

非大寫字母

既不是a也不是A

數字

“Hello!”

“happy~”

“1993年”

  • 問號“?”

    比如我們在語料庫中搜索詩人“李白”或者“李太白”,此時方括號就無法幫助我們,因為[]只能表示xx或者XX,但是不能表示有xx或者沒xx。此時可以用“?”來表示前一個字元有或者無。

正則

匹配

/李太?白/

/times?/

“李白”或者“李太白”

time或者times

  • “Kleene*”

    當正則表示式用來表示重複的字元時,比如在下載檔案時,出現了下面的下載進度:

99.9%

99.99%

99.999%

99.9999%

……

此時我們可以用/9*/來表示重複了“0或者若干次”的字元“9”,因此想表示出現了一次或者多次的“9”,需要用/99*/。

因此/99\.99*%/可以用來表示上述進度條。(此處的“.”需要轉譯,因為我們不想讓他表示為萬用字元)

稍微複雜點:

/[10]*/可以用來表示一個二進位制串,比如“1010100001110001”

  • “Kleene+”

但是我用/99*/來表示重複了“0或者若干次”的字元“9”時總覺得多寫了一個“9”很不爽,這時有沒有辦法幫我們省掉多打一個“9”的時間呢?

/9+/就可以了~

因此使用/[10]+/來搜尋語料中的二進位制字串看起來更順手

  • 萬用字元“.”

哎那個馬什麼民,幫我把襪子洗一下。

這樣說話是很不禮貌的,但是當我們確實忘了別人名字時怎麼辦呢?

正則表示式同樣可以解決這個問題。

正則裡面有一個點號,萬用字元(/./)可以表示任何字元。

/馬.民/可以在你的班級花名冊裡面搜尋到所有叫“馬X民”的人。

正則

匹配

模式例子

/[beg.n]/

beg和n中包含一個字元的字串

begin,beg‘n,begun

當/./和/*/或者/+/碰到時,什麼神奇的事情會發生呢?

比如我們想知道有一天 馬X民對黃偉做了什麼事情,怎麼寫正則來在班級日誌裡面縮小搜尋範圍呢?

/馬.民.+黃偉/就可以表示在一個長字串裡面,符合馬X民bulabula黃偉的句子。

  • 錨號“^”和“$”

顧名思義,錨號是用來把正則“錨”在字串的特定位置的。最普通的錨號是“^”和“$”,當“^”用作錨號的時候,表示一行的開始。比如/^The/就表示單詞The必須出現在一句話的開頭。相反“$”表示一行的結尾。

回到上面的例子,比如我們想在班級日誌裡面找到“馬興民xxx黃偉。”這樣的句子,就可以使用錨號來定位。/^馬興民.+黃偉。$/

  • 詞界“\b”“\B”

\b表示詞界,\B表示非詞界。

首先,在計算機語言裡面,什麼是一個詞呢。從技術上說,詞被定義為數字、下劃線、或者字母的任何序列。

比如我們在搜尋單詞“a”的時候,如果僅僅用/a/,同樣會匹配到類似於“happy”這樣的單詞,但是如果用/\ba\b/的話,就會只找到單詞a。比如“I am a handsome man.”

它僅僅會匹配到單詞“a”而非“am”。

  • 析取符“|”

析取符表示或者。

前面有個小夥子很眼熟,我記得他的名字叫馬興民或者黃偉。現在我開啟線上班級花名冊,輸入正則/黃偉|馬興民/,一下就找到了兩個人的資訊和照片,一看哦都不是。

析取符就是用來表示或者,/a|b/表示a或者b。

在英文語料中,有時候會出現名詞的複數形式比如cat和cats,這種形式我們很容易表達。但是有些複數比如family的複數families該如何表達呢。

首先famil串已經是固定的了,這時我們只需要尾串跟上y或者ies即可,此時我們使用圓括號運算子(),將一個模式括起來,使得它就像一個單獨的字元。因此如果我們想找到語料中的family和families時,需要用/famil(y|ies)/,析取符僅僅運用於字尾y或者ies。

三:

  •  通用字符集的替換

正則

擴充表示式

匹配

\d

\D

\w

\W

\s

\S

[0-9]

[^0-9]

[a-zA-Z0-9]

[^\w]

[_\r\t\n\f]

[^\s]

數字字元

非數字字元

數字字母下劃線

相反

表格,換行等空白區域

非空白區域

  • 計數符

正則

匹配

*

+

?

{n}

{n,m}

{n,}

零或多

一或多

零或一

出現n次

n到m次

至少n次

  •  ? 貪婪模式與非貪婪模式

     比如在HTML中有許多標籤<div>part1</div><div>part2</div><div>part3</div><div>part4</div>

    使用<div>.*</div>匹配到的是:<div>part1</div><div>part2</div><div>part3</div><div>part4</div>,此時為貪婪模式。

    使用<div>.*?</div>匹配到的是:<div>part1</div>

  • (?<=exp) (?=exp)零寬斷言

    (?<=exp) 表示匹配exp之後的,(?=exp)表示匹配exp之前的。

    比如上面標籤例子:<div>part1</div><div>part2</div><div>part3</div><div>part4</div>

    如果我們僅僅想拿到標籤裡面的內容,就可以使用零寬斷言:

    (?<=<div>).*(?=</div>)此時匹配到:part1</div><div>part2</div><div>part3</div><div>part4

    結合上面的零寬斷言:

    (?<=<div>).*(?=</div>)此時匹配到:part1 part2 part3 part4

    

  • 一個開發思路的例子

    當我們想在語料中查詢英語冠詞the的時候,隨手寫下正則/the/。

    但是隨後發現有些地方是不完善的,比如當the出現在開頭的時候,就是The,因此我們把正則改成/[tT]he/。

    此時這個正則還是不完善的,因為它會找到諸如There,other這樣的單詞,因此我們給它加上了詞界/\b[tT]he\b/。

    問題又來了,假如我們不想把下劃線和數字作為詞界,我們還希望能夠找到形如 _the,the99這樣的詞。此時我們需要給the的兩段加上限制:不能為字母。於是正則變成了/[^a-zA-Z][tT]he[^a-zA-Z]/。

    萬事大吉了嗎?這時候我們發現,當the出現在開頭的時候,正則找不到它,因為我們規定了the的開頭必須有一個非英文字元,因此我們需要修改開頭為,the出現在開頭或者開頭有一個非英文字元。即/(^|[^a-zA-Z])[tT]he[^a-zA-Z]/。

    終於到這裡,一個符合要求的簡單的定冠詞the被搜尋了出來。

    平時書寫正則的時候也要注意,提升準確率,提升覆蓋率。