一個斷言就是一個對當(dāng)前匹配位置之前或之后的字符的測試, 它不會實(shí)際消耗任何字符。簡單的斷言代碼有\(zhòng)b、\B、 \A、 \Z、\z、 ^、$ 等,在 轉(zhuǎn)義序列(反斜線) 中有描述。 更加復(fù)雜的斷言以子組的方式編碼。 它有兩種類型: 前瞻斷言(從當(dāng)前位置向前測試)和后瞻斷言(從當(dāng)前位置向后測試)。
一個斷言子組的匹配還是通過普通方式進(jìn)行的,
不同在于它不會導(dǎo)致當(dāng)前的匹配點(diǎn)發(fā)生改變。
前瞻斷言中的正面斷言(斷言此匹配為真)以 ”(?=” 開始,消極斷言以 ”(?!” 開頭。比如,
\w+(?=;)
匹配一個單詞緊跟著一個分號但是匹配結(jié)果不會包含分號,
foo(?!bar)
匹配所有后面沒有緊跟 ”bar” 的 ”foo” 字符串。
注意一個類似的模式
(?!foo)bar
它不能用于查找之前出現(xiàn)所有不是 ”foo” 的 ”bar” 匹配,
它會查找到任意的 ”bar” 出現(xiàn)的情況,
因?yàn)?(?!foo) 這個斷言在接下來三個字符時 ”bar” 的時候是永遠(yuǎn)都 true
的。
前瞻斷言需要達(dá)到的就是這樣的效果。
后瞻斷言中的正面斷言以”(?<=”開始, 消極斷言以”(?<!”開始。比如,
(?<!foo)bar
用于查找任何前面不是 ”foo” 的 ”bar”。
后瞻斷言的內(nèi)容被嚴(yán)格限制為只能用于匹配定長字符串。但是,如果有多個可選分支,
它們不需要擁有相同的長度。比如
(?<=bullock|donkey)
是允許的,
但是
(?<!dogs?|cats?)
將會引發(fā)一個編譯期的錯誤。在最上級分支可以匹配不同長度的字符串是允許的。
相比較于 perl 5.005 而言,它會要求多個分支使用相同長度的字符串匹配。
(?<=ab(c|de))
這樣的斷言是不允許的,
因?yàn)樗鼏蝹€的頂級分支可以匹配兩個不同的長度,
但是它可以接受使用兩個頂級分支的寫法
(?<=abc|abde)
這樣的斷言實(shí)現(xiàn),
對于每個可選分支,暫時將當(dāng)前位置移動到嘗試匹配的當(dāng)前位置之前的固定寬度處。
如果在當(dāng)前沒有足夠的字符就視為匹配失敗。后瞻斷言與一次性子組結(jié)合使用可以用來匹配字符串結(jié)尾;
一個例子就是在一次性子組上給出字符串結(jié)尾。
多個斷言(任意順序)可以同時出現(xiàn)。
比如
(?<=\d{3})(?<!999)foo
匹配前面有三個數(shù)字但不是 ”999” 的字符串 ”foo”。注意,
每個斷言獨(dú)立應(yīng)用到對目標(biāo)字符串該點(diǎn)的匹配。 首先它會檢查前面的三位都是數(shù)字,
然后檢查這三位不是 ”999”。
這個模式不能匹配 ”foo” 前面有三位數(shù)字然后緊跟 3 位非 999 共 6 個字符的字符串,比如,
它不匹配 ”123abcfoo”。
匹配 ”123abcfoo” 這個字符串的模式可以是
(?<=\d{3}…)(?<!999)foo
。
這種情況下,第一個斷言查看(當(dāng)前匹配點(diǎn))前面的 6 個字符,檢查前三個是數(shù)字, 然后第二個斷言檢查(當(dāng)前匹配點(diǎn))前三個字符不是 ”999”。
斷言可以以任意復(fù)雜度嵌套。
比如
(?<=(?<!foo)bar)baz
匹配前面有 ”bar” 但是 ”bar” 前面沒有 ”foo” 的 ”baz”。
另外一個模式
(?<=\d{3}...(?<!999))foo
則匹配前面有三個數(shù)字字符緊跟 3 個不是 999 的任意字符的 ”foo”。
斷言子組時非捕獲子組,并且不能用量詞修飾, 因?yàn)閷ν患伦龆啻螖嘌允菦]有意義的.如果所有的斷言都包含一個捕獲子組, 那么為了在整個模式中捕獲子組計數(shù)的目的,它們都會被計算在內(nèi)。然而, 子字符串的捕獲僅可以用于正面斷言,因?yàn)閷τ谙麡O的斷言是沒有意義的。
將斷言計算在內(nèi),可以擁有的最大子組數(shù)量是 200 個。