【发布时间】:2017-02-09 08:19:13
【问题描述】:
TL;DR
re.search("(.)(?!.*\1)", text).group() 不匹配文本中包含的第一个非重复字符(它总是返回第一个非重复字符处或之前的字符,如果没有非重复字符,则返回字符串末尾之前的字符.我的理解是,如果没有匹配项,re.search() 应该返回 None 。
我只是想了解为什么此正则表达式无法使用 Python re 模块按预期工作,而不是任何其他解决问题的方法
全背景
问题描述来自https://www.codeeval.com/open_challenges/12/。我已经使用非正则表达式方法解决了这个问题,但重新访问它以扩展我对 Python 的 re 模块的理解。
我认为可行的正则表达式(命名与未命名的反向引用)是:
(?P<letter>.)(?!.*(?P=letter)) 和 (.)(?!.*\1)(在 python2 和 python3 中的结果相同)
我的整个程序是这样的
import re
import sys
with open(sys.argv[1], 'r') as test_cases:
for test in test_cases:
print(re.search("(?P<letter>.)(?!.*(?P=letter))",
test.strip()
).group()
)
一些输入/输出对是:
rain | r
teetthing | e
cardiff | c
kangaroo | k
god | g
newtown | e
taxation | x
refurbished | f
substantially | u
根据我在https://docs.python.org/2/library/re.html阅读的内容:
-
(.)创建一个与任何字符匹配的命名组,并允许以后将其反向引用为\1。 -
(?!...)是一个否定的前瞻,它将匹配限制在...不匹配的情况。 -
.*\1表示任意数量(包括零)的字符,后跟之前与(.)匹配的任何字符 -
re.search(pattern, string)仅返回正则表达式模式产生匹配的第一个位置(如果找不到匹配则返回 None) -
.group()等价于.group(0),它返回整个匹配项
我认为这些部分应该可以解决上述问题,并且它确实像我认为的大多数输入一样工作,但在teething 上失败了。向它抛出类似的问题表明,如果它们是连续的,它似乎会忽略重复的字符:
tooth | o # fails on consecutive repeated characters
aardvark | d # but does ok if it sees them later
aah | a # verified last one didn't work just because it was at start
heh | e # but it works for this one
hehe | h # What? It thinks h matches (lookahead maybe doesn't find "heh"?)
heho | e # but it definitely finds "heh" and stops "h" from matching here
hahah | a # so now it won't match h but will match a
hahxyz | a # but it realizes there are 2 h characters here...
hahxyza | h # ... Ok time for StackOverflow
我知道lookbehind 和negative lookbehind 仅限于最多3 个字符的固定长度字符串,并且即使它们评估为固定长度的字符串也不能包含反向引用,但我没有看到文档指定对负前瞻的任何限制。
【问题讨论】:
-
这就是您正确提出正则表达式问题的方式。干得好。
-
我通常会放弃草稿问题,因为我在记录我的尝试、研究和期望时找到了答案——或者在问题完全写完后我正在修复格式时我很少找到答案。不过,这完全让我无法理解。
-
我发现我自己也经常遇到这种情况。不太常见的是网站上的一个相当新的人在来到这里之前提出了一个正则表达式问题,并有如此有据可查的尝试来解决问题。令人耳目一新。
-
注意:当前答案不提供此标题的唯一正则表达式解决方案:正则表达式匹配第一个非重复字符。他们只说 OP 为何以及如何错误地认为他的解决方案背后的想法是错误的。这个赏金是在这个问题上开始的,它可以得到这个问题的解决方案。
-
@revo 给你,我添加了一个简单的 .NET 和一个 Python 解决方案;)我不确定这是否适用于 PCRE,我需要考虑一下。
标签: python regex regex-lookarounds