否定前瞻断言在python中不起作用[重复]
Posted
技术标签:
【中文标题】否定前瞻断言在python中不起作用[重复]【英文标题】:negative lookahead assertion not working in python [duplicate] 【发布时间】:2012-12-02 01:12:36 【问题描述】:任务: - 给定:图像文件名列表 - 待办事项:创建一个文件名不包含单词“thumb”的新列表 - 即仅针对非缩略图图像(使用 PIL - Python Imaging Library)。
我试过r".*(?!thumb).*"
,但失败了。
我找到了解决方案(在 *** 上),在正则表达式前面加上 ^
并将 .*
放入否定的前瞻中:r"^(?!.*thumb).*"
,现在可以使用了。
问题是,我想了解为什么我的第一个解决方案不起作用,但我没有。 由于正则表达式足够复杂,我真的很想了解它们。
我所理解的是^
告诉解析器以下条件匹配字符串的开头。但是(不工作)第一个示例中的.*
不是也从字符串的开头开始吗?
我认为它会从字符串的开头开始,并在到达“拇指”之前搜索尽可能多的字符。如果是这样,它将返回不匹配。
有人能解释一下为什么r".*(?!thumb).*"
不起作用但r"^(?!.*thumb).*"
起作用吗?
谢谢!
【问题讨论】:
Ummm - “不包含 word 拇指” - 强调我的...否则,为什么要使用正则表达式? 虽然正则表达式的使用不适用于这项任务(可能是家庭作业?),但最后一个问题仍然存在。 嗨,乔恩,感谢您的快速回复。我使用了正则表达式,因为我开始使用正则表达式将路径分解为目录和文件名。我是 Python 新手,在尝试处理这些任务时,我偶然发现了正则表达式。由于我是 Python 新手,我可能不知道其他(更简单的?)解决方案。你能解释一下对“词”的强调吗? 'Word' 为 16 位整数? 好的,谢谢mmgp,得到了关于它为什么不适用的评论(任务:创建列表...),我真正的问题:如何在Python 中的正则表达式? 正如@mmgp 提到的,我仍然想知道,为什么第一个正则表达式示例不起作用而第二个示例起作用。 【参考方案1】:有人可以解释为什么
r".*(?!thumb).*"
不起作用但是r"^(?!.*thumb).*"
有吗?
第一个将始终匹配,因为.*
将消耗所有字符串(因此它后面不能有任何东西,否则否定前瞻失败)。第二个有点复杂,将从行首开始匹配,直到遇到'thumb'为止的最多字符,如果存在,则整个匹配失败,因为该行确实以某些内容开头,然后是'thumb' .
第二个更容易写成:
'thumb' not in string
not re.search('thumb', string)
(而不是匹配)
正如我在 cmets 中提到的,您的问题是:
文件名不包含单词“thumb”
因此您不妨考虑是否应该排除thumbs up
。
【讨论】:
谢谢@Jon。.*
将使用该字符串的注释起到了作用。所以在.*
被解析之后,没有什么可以评估并且解析器直接到字符串的末尾?如果是这样,我现在明白为什么^(?!.*thumb).*
解决方案确实有效:它在否定前瞻中包含“拇指”一词,从而防止.*
匆匆过去。如果没有尾随.*
,它会给出一个空的结果/匹配(但仍然是一个结果/匹配)。您提到的另外两个符号(以及来自@larsks 的符号)当然更容易完成这项任务,所以谢谢!
@erik 觉得你说得比我好 :)
关于:“所以你不妨考虑一下thumbs up
是否应该被排除在外。”我的(图像)文件名被命名为filename.jpg
和filename_thumb.jpg
,因此在我的情况下,简单地在字符串中的某处搜索 thumb 不会造成问题。谢谢指出!【参考方案2】:
(该死,乔恩打败了我。哦,好吧,无论如何你都可以看看例子)
正如其他人所说,正则表达式不是这项工作的最佳工具。如果您正在使用文件路径,请查看os.path。
至于过滤你不想要的文件,你可以在剖析路径后执行if 'thumb' not in filename: ...
(其中filename
是str
)。
对于后代,这是我对这些正则表达式的看法。 r".*(?!thumb).*"
不起作用,因为 .*
是贪婪的,并且前瞻的优先级很低。看看这个:
>>> re.search('(.*)((?!thumb))(.*)', '/tmp/somewhere/thumb').groups()
('/tmp/somewhere/thumb', '', '')
>>> re.search('(.*?)((?!thumb))(.*)', '/tmp/somewhere/thumb').groups()
('', '', '/tmp/somewhere/thumb')
>>> re.search('(.*?)((?!thumb))(.*?)', '/tmp/somewhere/thumb').groups()
('', '', '')
最后一个很奇怪……
另一个正则表达式 (r"^(?!.*thumb).*"
) 有效,因为 .*
在前瞻内,因此您不会遇到任何字符被盗的问题。实际上,您甚至不需要^
,这取决于您使用的是re.match
还是re.search
:
>>> re.search('((?!.*thumb))(.*)', '/tmp/somewhere/thumb').groups()
('', 'humb')
>>> re.search('^((?!.*thumb))(.*)', '/tmp/somewhere/thumb').groups()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'groups'
>>> re.match('((?!.*thumb))(.*)', '/tmp/somewhere/thumb').groups()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'groups'
【讨论】:
@Balthamos - 在您的示例中,我可以很好地看到第一个(.*)
消耗了完整的字符串,并且 ?
使其不贪婪(为什么为空?可能是因为 *
也允许 0 个匹配项?不是一个好主意)。我试过省略^
,结果是humb.jpg
。因此,似乎 (?!.*thumb) 会消耗以thumb
开头的所有内容,无论它之前是什么,而尾随的.*
会捕获所有不以thumb
开头的内容,即其余:humb.jpg
。为什么负前瞻不会抛出 no match 并且有有效结果对我来说仍然是一个谜。
好的,我试过 re.match
而不是 re.search
,它返回 no match。似乎re.match
做了^
在我的工作正则表达式示例中所做的事情。需要注意的是,如果正则表达式的其他部分可以匹配(.*
等),re.search
不会被匹配的负前瞻阻止。
虽然这并不能解释为什么会这样以及为什么^
与re.match
的工作方式相同。但我会改天再解决的;)。
'为什么是空的?也许是因为 * 也允许 0 个匹配项?不是一个想法'是的,你明白了。 “为什么负前瞻不会引发不匹配并且有有效结果对我来说仍然是一个谜”这对我来说也很奇怪。我需要仔细考虑一下,以便找到一个很好的理由来说明它为什么这样做。 re.match
必须匹配整个字符串(本质上是'^regex$'
) re.search
可以匹配字符串的任何部分(本质上是^.*regex.*$
)
也许仍然存在匹配,因为这是对负前瞻断言 (nla) 进行编程的方式——在这种情况下,它们可能不会像假设的那样被编程。所以 nla 基本上只是从re.search
中删除不匹配的部分,并且只有在re.match
的情况下才会导致不匹配。到目前为止我的推理。当我有更多时间时,我会尝试是否适用于所有情况。【参考方案3】:
忽略有关正则表达式的所有内容,您的任务似乎相对简单:
给定:图像文件名列表 todo:创建一个文件名不包含单词“thumb”的新列表 - 即仅针对非缩略图图像(使用 PIL - Python 图像库)。
假设您有一个看起来像这样的文件名列表:
filenames = [ 'file1.jpg', 'file1-thumb.jpg', 'file2.jpg', 'file2-thumb.jpg' ]
然后你可以得到一个不包含thumb这个词的文件列表:
not_thumb_filenames = [ filename for filename in filenames if not 'thumb' in filename ]
这就是我们所说的list comprehension,本质上是以下的简写:
not_thumb_filenames = []
for filename in filenames:
if not 'thumb' in filename:
not_thumb_filenames.append(filename)
对于这个简单的任务来说,正则表达式并不是必需的。
【讨论】:
感谢您的全面回答!如前所述,我不知道其他解决方案。我很久以前在 Perl 脚本中使用过正则表达式,因此它们是处理搜索/匹配问题时的第一个 goto 解决方案。以上是关于否定前瞻断言在python中不起作用[重复]的主要内容,如果未能解决你的问题,请参考以下文章
加速器在 Python Tkinter 中不起作用:如何修复 [重复]
Dataframe.rdd.map().collect 在 PySpark 中不起作用 [重复]
AngularJS、SweetAlert.js 在自定义指令中不起作用