在第五章中,我们已经学习了字符集,它可以匹配多个字符中的一个字符。选择符和字符集很类似,它可以匹配多个表达式中的任意一个字符。
如果你想搜索多个文本,例如cat或者dog,你可以使用竖线来分隔这两个文本:cat|dog
。如果你想要更多的选项,你可以对上面的例子进行扩展:cat|dog|mouse|fish
。
选择符的优先级在所有的正则操作符中是最低的。所以引擎会匹配竖线左侧所有的内容,或者右侧所有的内容。如果你想限制选择符所能到达的范围,你需要你用圆括号来增加一个匹配组。例如,如果你想匹配字符串中的单词cat或者dog,你需要使用以下表达式\b(cat|dog)\b
,这会告诉引擎匹配一个边界符,然后是cat或者dog,最后再匹配一个边界符。如果我们去除这个例子中的圆括号:\bcat|dog\b
,那么引擎将匹配\bcat
或者cat\b
。
在第四章中我们已经讲过,正则引擎总是返回最先匹配成功的结果,一旦有成功的匹配就停止搜索。引擎的这种特性导致选项的顺序会影响匹配结果。
假设我们现在想匹配一组程序中的方法名称:Get,GetValue,Set,SetValue。最直接的解决方案是:Get|GetValue|Set|SetValue
。让我们来看一下它是如何匹配SetValue这个字符串的。
首先正则引擎将第一个tokenG
和第一个字符S匹配,匹配没有成功。但是此时引擎通过学习整个表达式得知表达式中使用了选择符,所以还有其他选项可以进行匹配,也就是说字符S此时还不能确定是否匹配失败。引擎此时不会移动到下一个字符e,而是匹配选择符中的第二个选项GetValue
,和前一次相同,这个选项匹配也失败了。接着引擎尝试匹配第三个选项Set
,由于tokenS
、e
、t
能依次和字符串SetValue中的前三个字符匹配,所以Set
这个选项匹配成功了。
选择符中的某一个选项一旦匹配成功,引擎就认为整个选择符匹配成功了。在这里例子中除了选择符以外没有其他的token,所以引擎认为整个表达式匹配成功了。整个表达式匹配了字符串SetValue中的Set。
和我们预期的不同,表达式并没有匹配到完整的SetValue。有很多种方式可以解决这个问题。一种方法是改变选项的顺序,如果我们使用GetValue|Get|SetValue|Set
那么SetValue将在Set之前匹配,所以它可以匹配的完成的结果。我们可以使用问好操作符把四个选项压缩为两个,例如Get(Value)?|Set(Value)?
。因为?
是贪婪的,所以SetValue会比Set先匹配。
更理想的解决方法是直接匹配完整的单词,因为我们并不想匹配SetValueFunction中的Set或者SetValue。正确的表达式是:\b(Get|GetValue|Set|SetValue)\b
或者\b(Get(Value)?|Set(Value)?)\b
。其实我们可以进一步压缩为\b(Get|Set)(Value)?\b.
,因为所有选项的结尾都是Value。
如果文章出现错误,请给我提Issues - - Github地址
需要进一步翻译的内容:
- 问好操作符