Anrs Hu

你所知的一切…

PCRE/Python 下的 re 细节(4) — 条件分支(conditional)

without comments

所谓条件分支,就是“当 x 成功捕获的话,则执行多选分支 y,否则执行多选分支 z”,也就是说这个东西在表达式中实现了 if/then/else 的功能。条件分支的语法比较类似于多选分支,只是更复杂,像这样:…(?(1)then|else)…

(?(1)… 就表示开始一个条件分支的匹配,数字 1 的意思是测试整个表达式中第 1 个反向引用是否有参与匹配,如果有则匹配表达式 then,否则匹配表达式 else。看 recipe 2.17 中表达式 (a)?b(?(1)c|d) 的匹配过程。(a)?b(?(1)c|d) 如期望的那样可以匹配目标文本 abc、bd、abd,但匹配不到 bc。

匹配目标文本 abc 时,(a)? 匹配成功,\1 捕获到字符 a,然后前推当前表达式字符到 b,再次匹配成功,继续前推当前表达式字符。这时引擎看到 (?(1) 就识别出这是一个条件分支匹配,于是测试反向引用 1 有没有参与匹配,发现有,于是执行 | 前的部分,也就是匹配字符 c,依然匹配成功,于是整个表达式宣告匹配成功。

匹配目标文本 bd 的过程:(a)? 匹配失败,\1 没有捕获到任何内容,然后匹配过程与匹配 abc 时类似,直到当引擎在条件分支中发现反向引用 1 没有参与匹配,会将 | 后的部分 d 拿来进行匹配,还是匹配成功,于是整个表达式匹配成功。匹配 bc 时则是当引擎发现反向引用 1 没有参与匹配时,就将 | 后的 d 拿来匹配时,结果匹配失败,于是整个表达式也相应匹配失败。

目标文本 abd 的匹配过程是比较有趣的,首先 (a)? 匹配成功,\1 捕获到字符 a,前推当前表达式和当前目标文本,b 和 b 匹配成功,继续前推表达式和目标文本,因为 \1 有内容,所以当前表达式字符为 c,c 和 d 匹配失败,但并不意味着整个表达式也匹配失败了,不要忘了 (a)? 中的 ? 是可以回溯的,所以当前表达式字符和当前目标文本字符均发生回溯,接下来的匹配过程就跟匹配 bd 的过程完全一致了,最终整个表达式还是匹配成功。而如果期望 abd 匹配失败的话,只要在 (a)? 前增加一个 ^ 锚就好了。

有个值得注意的地方是表达式 (a)?b(?(1)c|d) 中 (a)? 的 ? 是在括号外面的,如果写成 (a?)b(?(1)c|d) 的话,即使 (a?) 匹配失败,但 (?(1) 还是会返回 true,因为 (a?) 始终都被认为是有参与匹配的,所以 (?(1)c|d) 总是 | 前的 c 参与后续的匹配过程。

Written by admin

October 27th, 2009 at 4:16 am

Posted in Regular Expression

Tagged with

Leave a Reply