有没有办法按照发生的顺序匹配唯一的字符组(下面的例子中的单词),纯粹是在正则表达式中?如果是这样,该表达式如何在效率上与非正则表达式解决方案进行比较?我正在使用Python的风格,但我也会对任何其他风格的解决方案感兴趣。
以下是一个示例案例:
string = 'the floodwaters are rising along the coast'
unique = ['the', 'floadwaters', 'are', 'rising', 'along', 'coast']
在Python-regex混合解决方案中,我可以匹配我想要的组,并使用列表推导来删除重复项,同时保持顺序。
groups = re.findall('[a-zA-Z]+', string)
unique = [g for i, g in enumerate(groups) if g not in groups[:i]]
网站上存在类似问题,例如one that addresses matching unique words。然而,接受的答案中的表达式与给定组的最右侧出现匹配,而我想匹配第一次出现。这是表达式:
(\w+\b)(?!.*\1\b)
答案 0 :(得分:2)
只有使用无限宽度的后备才能实现此类任务的正则表达式解决方案。
然而,当输入相对较短时,这样的正则表达式解决方案应该仅考虑使用:输入字符串中超过100个字会使其变得非常慢由于回溯在这种情况下是不可避免的。因此,仅仅为了学习目的,我将分享仅在.NET和Python PyPi regex
库中支持的正则表达式(它也可以在Vim中进行,因为它的外观也是无限宽度,但我想这个强大的工具还有更简单的方法。)
(?s)\b(\w+)\b(?<!^.*\b\1\b.*\b\1\b)
请参阅regex demo
(?s)
部分是内联修饰符,使.
匹配所有换行符。您可以在Python regex.DOTALL
中使用regex
。
<强>详情
\b
- 初始字边界(\w+)
- 第1组:一个或多个单词字符\b
- 尾随字边界(?<!^.*\b\1\b.*\b\1\b)
- 如果匹配到组1中的单词恰好在其自身之前出现一次,即如果紧接在当前位置的左侧(即紧接着),则无限宽度负向后看将导致匹配失败捕获的单词),有一系列模式:
^
- 字符串开头.*\b\1\b
- 任意零个或多个字符,尽可能多,然后与第1组中的整个字相同的值.*\b\1\b
- 与上述相同(需要匹配捕获的单词,因为在消费后的单词 后视镜中的.*
导致大量回溯,一般来说,模式的工作速度相当慢,而且输入量很大,最终可能导致超时。