交替与原子团无关。原子团的重点是避免回溯。这主要有两个原因:
- 当正则表达式无论如何都将无法匹配时,请避免不必要的回溯。
- 避免回溯到您不想找到匹配项的表达式部分
您要求提供一个没有交替的原子分组示例。
让我们看看这两种用途。
A.避免失败时回溯
例如,考虑以下两个字符串:
name=Joe species=hamster food=carrot says:{I love carrots}
name=Joe species=hamster food=carrot says:{I love peas}
假设我们想要找到一个格式正确的字符串(它有key=value 标记)并且在标记之后有carrots,可能在says 部分。尝试这样做的一种方法可能是:
非原子版本
^(?:\w+=\w+\s+)*.*carrots
这将匹配第一个字符串而不是第二个。很高兴。或者……我们真的吗?不开心有两个原因。我们将在 B 部分中研究第二个原因(原子团的第二个主要原因)。那么第一个原因是什么?
好吧,当您在 RegexBuddy 中调试失败案例时,您会看到它在引擎决定它无法匹配第二个字符串之前执行引擎 401 步骤。之所以这么长,是因为在匹配令牌并且未能匹配says:{I love peas} 中的carrots 之后,引擎会回溯到(\w+=\w+\s+)*,希望在那里找到carrots。现在让我们看一个原子版本。
原子版本
^(?>(?:\w+=\w+\s+)*).*carrots
在这里,原子组防止引擎回溯到(?:\w+=\w+\s+)*。结果是在第二个字符串上,引擎在 64 个步骤中失败。比 401 快很多!
B.避免回溯到不需要匹配的字符串部分
保持相同的正则表达式,让我们稍微修改一下字符串:
name=Joe species=hamster food=carrots says:{I love carrots}
name=Joe species=hamster food=carrots says:{I love peas}
我们的原子正则表达式仍然有效(它匹配第一个字符串但不匹配第二个字符串)。
但是,非原子正则表达式现在匹配两个字符串!那是因为在says:{I love peas}中找不到carrots后,引擎回溯到token中,在food=carrots中找到carrots
因此,在这种情况下,原子组是一种方便的工具,可以跳过我们不想找到 carrots 的字符串部分,同时仍确保其格式正确。