想讓一個名詞聽起來特別高大上,最簡單的方法就是加很多修飾語。比如多源異構群智協(xié)同負反饋深度神經(jīng)網(wǎng)絡(當然了,這是我瞎編的)。在正則表達式中,有一種東西叫斷言,它的修飾語也很多:
- 零寬正向先行斷言
- 零寬負向先行斷言
- 零寬正向后行斷言
- 零寬負向后行斷言
斷言之所以叫“零寬”,是因為它們不會消費字符串,可以理解為斷言匹配的是位置。
斷言之所以叫“斷言”,是因為它們用來產(chǎn)生一個True\False的判定結果。
正向和負向分別指的是“應該出現(xiàn)”和“不應該出現(xiàn)”。
先行和后行分別指的是“此位置之后”和“此位置之前”。
這些東西有哪些實際的用途呢?Talk is cheap,show you the code!注意:以下例子是用scala寫的,這樣就避免了java字符串中“\”的轉義。

負向斷言例子1
假設有幾個文件全名:"file1.mp3","file2.bat","file3.txt",需要把英文句號之前的文件名提取出來。在這個過程中,需要忽略所有bat文件和mp3文件。
val pattern ="""(\w+)\.(?!bat|mp3)(\w+)""".r
val result = List("file1.mp3", "file2.bat", "file3.txt")
.flatMap(s => {
s match {
case pattern(name, _) => List(name)
case _ => Nil
}
})
這個負向先行斷言意思是此位置(句號后面)后面的字符串不能匹配“bat|mp3”,也就排除了bat和mp3擴展名。
負向斷言例子2
例如需要在標書中需要提取采購聯(lián)系人的姓名。
采購人:大連理工大學
聯(lián)系人:張三
這時采購聯(lián)系人可以認為是張三
采購人:大連理工大學
代理機構:大連理工代理公司
聯(lián)系人:李四
這時李四不能認為是采購聯(lián)系人,他應該是代理機構聯(lián)系人。(別問我為什么不用如日中天、如火如荼的自然語言處理,而非要用正則表達式作繭自縛)
這時的正則表達式為
(采購人)(?!.*代理機構).*?(聯(lián)系人:)(?<name>\S+)
它要求“采購人”后面出現(xiàn)“聯(lián)系人”,但是“采購人”后面不能有“代理機構”。
事實上,嚴格來說應該要求“采購人”和“聯(lián)系人”之間不能有“代理機構”,anyway......who cares?
正向斷言例子1
提取獲取標書的開始時間。
需要購買標書的投標人,請于3月15日到26日登錄某某網(wǎng)站
招標文件下載時間:北京時間3月15日至3月22日
這個正則表達式要求后面有日期,前面要出現(xiàn)“購買標書”、“招標文件下載”等關鍵詞,這些關鍵詞是特定名詞和特定動詞的組合。
(標書|招標文件|購買|下載).*(?<month>\d+)月(?<day>\d+)日
這個正則表達式問題在于名詞和動詞沒有要求同時出現(xiàn)。
((標書|招標文件) .*(購買|下載).*)|((購買|下載).*(標書|招標文件) .*)(?<month>\d+)月(?<day>\d+)日
這個要求倒是嚴格了,但是也太長了吧,增加了名詞和動詞時修改也不方便啊,要改兩個地方呢,容易出錯。
(?<=(標書|招標文件).*)(?<=(購買|下載).*)(\d+)月(\d+)日
這個正向斷言則解決了以上兩個問題。
正向斷言例子2
常見的密碼強度驗證一般都要求:
- 8-12位
- 必須有大寫字母
- 必須有小寫字母
- 必須有數(shù)字
^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).{8,12}
這個正則表達式還是挺有用的,說不定哪次面試就用上了呢?。?!