正则表达式正向回顾后 + 负向先行断言

4
给定字符串"A B C a b B",我想要匹配重复的单词(不考虑大小写)。期望的结果是匹配"A"和"B"(第一次出现的A和B)或"a"和"b"(最后一次出现的a和b)。
编辑:我只想匹配单词的第一次或最后一次出现。
我知道这个问题可以通过拆分字符串并计算每个标记(将其转换为小写)来更好地回答。然而,我想尝试制定一个正则表达式来帮助我找到这些单词,只是为了练习。
我的第一次尝试是:(?=\b(\w+)\b.*\b(\1)\b)(\1),但它匹配第一个A、第一个B和第二个b(A B b)。
我想通过使用正向后查和负向前查来获取重复单词的最后一个实例:(?<=.*(?!.*(\w+).*)\1.*)\b\1\b(在我的头脑中,它被翻译为“之前已匹配过但不会再次匹配的单词”)。
很不幸,它对我不起作用。
能否以这种方式使用正向后查和负向前查?我的正则表达式能否修复?我已经尝试在C#中解决它。
1个回答

2

有趣的难题。这是我的解决方案:

(\b\w+\b)(?:(?=.*?\b\1\b)|(?<=\b\1\b.*?\1))

演示

推理如下:

  • 匹配一个单词: (\b\w+\b)

  • 然后要么: (?:...|...)

    • 确保它稍后会再次出现: (?=.*?\b\1\b)
    • 或者它已经在之前出现过: (?<=\b\1\b.*?\1)

      lookbehind中的第二个\1匹配刚刚匹配的单词。第一个\1是真正的重复。


编辑后的问题答案:

如果您只想匹配重复单词的第一次出现,我们可以稍微修改上面的模式:

(\b\w+\b)(?=.*?\b\1\b)(?<!\b\1\b.*?\1)

演示

现在的逻辑是:

  • 匹配一个单词:(\b\w+\b)
  • 确保它再次出现:(?=.*?\b\1\b)
  • 并确保它之前没有出现过:(?<!\b\1\b.*?\1)

    (与之前相同,只不过使用了负向回顾后发)


我想只匹配重复的单词一次。我编辑了问题。抱歉。 - Eugene Krapivin
@nocgod 没问题,我已经扩展了答案。 - Lucas Trzesniewski
@Lucas_Trezsniewski 太好了!我一直在移动那些部件,不知道为什么我没有尝试简单的解决方案! - Eugene Krapivin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接