《正則表達式經典實例(第2版)》——2.6 匹配完整單詞
本節書摘來自異步社區《正則表達式經典實例(第2版)》一書中的第2章,第2.6節,作者: 【美】Jan Goyvaerts , Steven Levithan著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看
2.6 匹配完整單詞
問題描述
創建一個正則表達式來匹配My cat is brown中的cat,同時不能匹配category或是bobcat。再創建一個正則表達式來匹配staccato中的cat,同時不能匹配到上麵的3個目標字串。
解決方案
單詞邊界
\bcat\b
正則選項:無
正則流派:.NET、Java、JavaScript、PCRE、Perl、Python、Ruby
非單詞邊界
\Bcat\B
正則選項:無
正則流派:.NET、Java、JavaScript、PCRE、Perl、Python、Ruby
討論
單詞邊界
正則表達式記號‹\b›被稱作是單詞邊界(word boundary)。它會匹配一個單詞的開始或結束。就它自身而言,所產生的是一個長度為0的匹配。‹\b›也是一個定位符,這與在前一個小節中介紹過的記號是一樣的。
嚴格來講,‹\b›會匹配如下3種位置:
在目標文本的第一個字符之前,如果第一個字符是單詞字符;
在目標文本的最後一個字符之後,如果最後一個字符是單詞字符;
在目標文本的兩個字符之間,其中一個是單詞字符,而另外一個不是單詞字符。
如果要使用正則表達式來進行“隻匹配完整單詞”的查找,那麼隻需要把該單詞放在兩個單詞邊界之間,就像我們前麵給出的‹\bcat\b›。第一個‹\b›要求‹c›出現在字符串的最開始處,或者是在一個非單詞字符後麵。第二個‹\b›要求‹t›出現在字符串的最末尾處,或者是在一個非單詞字符前麵。換行符被認為是非單詞字符。如果換行符緊跟在一個單詞字符後麵,那麼‹\b›會匹配換行符後麵的位置。它同樣會匹配緊跟著一個單詞字符之前的換行符。這樣的話,一個占據了一整行的單詞也可以通過一個“隻匹配完整單詞”的查找來發現。‹\b›不會受到“多行”模式或是‹(?m)›的影響,這也是本書把“多行”模式稱為“^和$匹配換行處”的原因之一。
本書中介紹的所有流派都不提供可以隻匹配單詞之前或者隻匹配單詞之後的單獨記號。除非想要創建一個正則式隻包含單詞邊界,而不包含任何其他內容,否則這些單獨記號是不必要的。在正則表達式中,位於‹\b›之前和之後的記號會決定‹\b›可以匹配的位置。在‹\bx›和‹!\b›中的‹\b›隻會匹配一個單詞的開始。而在‹x\b›和‹\b!›中的‹\b›隻會匹配一個單詞的結束。‹x\bx›和‹!\b!›則永遠不會匹配任何位置。
如果確實隻想匹配一個單詞之前或之後的位置,可以使用順序環視(lookahead)和逆序環視(lookbehind)。實例2.16講解了順序環視和逆序環視。這種方法無法在JavaScript和Ruby 1.8中使用,因為它們不支持逆序環視。正則式‹(?<!\w)(?=\w)›匹配一個單詞開始的位置,其原理是檢查所匹配位置的前一個字符不是一個單詞字符,而後一個字符是單詞字符。‹(?<=\w)(?!\w)›則正相反:它匹配單詞結束的位置,其原理是檢查所匹配位置的前一個字符是單詞字符,而後一個字符不是單詞字符。關鍵是使用否定環視‹\w›而不是肯定環視‹\W›來檢查非單詞字符。因為字符串起始位置前麵沒有任何單詞字符(或者說沒有任何字符),所以‹(?<!\w)›可以匹配字符串的起始(第一個單詞之前)位置,而‹(?<=\W)›永遠不會匹配字符串的起始位置。同樣,‹(?!\w)›匹配字符串末尾(最後一個單詞之後)位置。所以兩個環視可以正確地匹配字符串起始的位置和末尾的位置。
非單詞邊界
‹\B›會匹配在目標文本中‹\b›不匹配的每一個位置。換句話說,‹\B›會匹配不屬於單詞開始或結束的每一個位置。
嚴格來講,‹\B›匹配如下5個位置:
在目標文本的第一個字符之前,如果第一個字符不是單詞字符;
在目標文本的最後一個字符之後,如果最後一個字符不是單詞字符;
在兩個單詞字符之間;
在兩個非單詞字符之間;
空串。
‹\Bcat\B›會匹配staccato中的cat。但是不會匹配My cat is brown、category或者bobcat中的cat。
如果想要進行與“隻匹配完整單詞”相反的查找(也就是說,不包括My cat is brown,但是包括staccato、category和bobcat),就需要采用多選結構來把‹\Bcat›和‹cat\B›組合成為‹\Bcat|cat\B›。其中,‹\Bcat›會匹配staccato和bobcat中的cat。‹cat\B›會匹配category中的cat(如果‹\Bcat›沒有匹配到,那麼它也可以匹配staccato)。實例2.8會詳細講解多選結構。
單詞字符
我們前麵一直在講單詞邊界,但是卻沒有涉及什麼是單詞字符(word character)。單詞字符就是可以在單詞中出現的字符。在實例2.3中的“簡寫”小節中,我們討論了哪些字符是包含在‹\w›中的,即單個的單詞字符。但是,對於‹\b›來說情形則有些不同。
雖然本書中的所有流派都支持‹\b›和‹\B›,但是它們對於到底哪些字符屬於單詞字符則有所不同。
在.NET、JavaScript、PCRE、Perl、Python和Ruby中,‹\b›都會匹配兩個字符之間的位置,其中一個字符可以由‹\w›匹配,而另外一個字符則可以由‹\W›匹配。‹\B›則總是匹配同時被‹\w›或‹\W›匹配的兩個字符之間的位置。
JavaScript、PCRE和Ruby隻把ASCII字符看做是單詞字符。‹\w›因此與‹[a-zA-Z0-9_]›是完全等同的。在這些流派中,你可以對像英語這樣的,單詞完全由不含讀音符號的A到Z的字母組成的情況,進行“隻匹配完整單詞”的查找。但是這些流派對於其他語言,如西班牙語或俄語,就無法進行“隻匹配完整單詞”的查找。
.NET把所有語言字母表中的字母和數字都當作單詞字符。你可以對任意語言中的單詞進行“隻匹配完整單詞”的查找,這其中也包括不使用拉丁字母的語言。
Python則為你提供了一個選項。在Python 2.x中,隻有在創建正則式時傳遞了UNICODE或是U標誌,非ASCII的字符才會被包括進來。在Python 3.x中,則默認包含非ASCII字符,不過可以使用ASCII或A標誌排除它們。這些標誌會對‹\b›和‹\w›產生相同的影響。
在Perl中,則Perl的版本和/adlu標誌決定‹\w›是純ASCII字符還是包括全部Unicode字母、數字和下劃線。實例2.3“簡寫”一節講解了更多細節。在所有的Perl版本中,‹\b›與‹\w›保持一致。
Java則表現得不是很一致。在Java 4到Java 6中,‹\w›隻匹配ASCII字符。在Java 7中,‹\w›默認值匹配ASCII字符,如果設置了UNICODE_CHARACTER_CLASS標誌則也匹配Unicode字符。但是Java所有版本‹\b›都是支持Unicode的,包括任何字母表。在Java 4到Java 6中,‹\b\w\b›會匹配一個單個的英語字母、數字或是在任何語言中都不會作為單詞一部分出現的下劃線。‹\bкошка\b›會正確匹配cat在俄語中對應的單詞,因為‹\b›是支持Unicode的。但是‹\w+›不會匹配任何泰國語單詞,因為在Java 4到Java 6中‹\w›隻會匹配ASCII字符。
最後更新:2017-06-02 19:35:27