匹配独特的群体,同时保持他们的秩序

时间:2017-08-31 23:09:03

标签: regex performance regex-group

有没有办法按照发生的顺序匹配唯一的字符组(下面的例子中的单词),纯粹是在正则表达式中?如果是这样,该表达式如何在效率上与非正则表达式解决方案进行比较?我正在使用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)

1 个答案:

答案 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 - 与上述相同(需要匹配捕获的单词,因为在消费后的单词
    • 之后使用了

后视镜中的.*导致大量回溯,一般来说,模式的工作速度相当慢,而且输入量很大,最终可能导致超时。