我有以下if语句:
if not fileName.startswith(".") and re.search("(.exe|.EXE)$", fileName) is not None and not fileName.endswith("-xyz.exe"):
pass
基本上,我想检查文件名不是以句点开头,以.exe或.EXE扩展名结尾,但不是以-xyz.exe扩展名结尾。我怎样才能摆脱startwith和endswith,并将这两个检查结合到正则表达式本身。
更新:我问,因为我想了解有关正则表达式的更多信息。根据可读性,我将确定是否值得使其更简洁。
更新2:我遇到了这种情况。我一直在寻找机会了解有关正则表达式的更多信息。这似乎是一个很好的机会,所以我试着亲自动手,直到我遇到困难。请不要给出非正则表达式解决方案或回应Mark Pilgrim关于“现在你有2个问题”的陈述,因为任何人都可以这样做。相反,向我证明现在我有两个问题,就像Mark Pilgrim继续他的课程一样。或者告诉我它很光滑。
答案 0 :(得分:2)
实际上这个很简单:
if re.search(
r"""# Always use VERBOSE when composing non-trivial regex!
^ # Anchor to start of string.
# Apply multiple lookahead assertions from string start:
(?!\.) # Assert does NOT begin with dot.
(?=.*\.exe$) # Assert DOES end with .EXE
(?!.*-xyz\.exe$) # Assert does NOT end with -XYZ.EXE
.* # Ok to match the filename (optional).
""",
subject, re.IGNORECASE | re.VERBOSE):
# Successful match
else:
# Match attempt failed
编辑:在仔细阅读您的问题之后,您似乎关注的是EXE的情况。在这种情况下,正则表达式也可以轻松处理它:
if re.search(
r"""# Always use VERBOSE when composing non-trivial regex!
^ # Anchor to start of string.
# Apply multiple lookahead assertions from string start:
(?!\.) # Assert does not begin with dot.
(?=.*\.(?:exe|EXE)$) # Assert DOES end with .EXE or .exe
(?!.*-xyz\.exe$) # Assert does NOT end with -xyz-exe
.* # Ok to match the filename (optional).
""",
subject, re.VERBOSE):
# Successful match
else:
# Match attempt failed
Edit2: John Machin已经指出,使用Python时,当您在寻找只能在目标字符串开头发生的匹配时,请使用^
的开头使用re.search
方法的字符串断言比使用re.match
慢得多(并且被认为是不好的做法)。考虑到这一点,这是一个改进的版本:
if re.match(
r"""# Always use VERBOSE when composing non-trivial regex!
# Apply multiple lookahead assertions from string start:
(?!\.) # Assert does not begin with dot.
(?=.*\.(?:exe|EXE)$) # Assert DOES end with .EXE or .exe
(?!.*-xyz\.exe$) # Assert does NOT end with -xyz-exe
.* # Ok to match the filename (optional).
""",
subject, re.VERBOSE):
# Successful match
else:
# Match attempt failed
答案 1 :(得分:2)
在开始尝试“缩短”代码之前学习使用基本正则表达式。
这篇文章re.search("(.exe|.EXE)$", fileName)
有三个不足之处:
(1)习惯使用原始字符串,即使它没有区别,因为那时你(和你的读者)不需要花时间来确定它是否重要。
(2)未转义.
匹配任何字符(换行符除外(默认情况下))。
(3)$
在字符串末尾的换行符之前匹配;你应该使用\Z
代替。如果不这样做,foo.exe\n
(如果您的输入是由未剥离\n
的人提供的,则容易错误地获取)将匹配。
您需要的是re.search(r"(\.exe|\.EXE)\Z", fileName)
更新,让所有认为re.search("^blahblah", ...)
都是个好主意的人都会受益:
>\python27\python -mtimeit -s"import re;s='x'*100" "re.match(r'foo',s)"
1000000 loops, best of 3: 1.2 usec per loop
>\python27\python -mtimeit -s"import re;s='x'*100" "re.search(r'^foo',s)"
100000 loops, best of 3: 2.91 usec per loop
>\python27\python -mtimeit -s"import re;s='x'*1000" "re.match(r'foo',s)"
1000000 loops, best of 3: 1.2 usec per loop
>\python27\python -mtimeit -s"import re;s='x'*1000" "re.search(r'^foo',s)"
100000 loops, best of 3: 18.5 usec per loop
答案 2 :(得分:1)
我不会使用正则表达式,只需将其包装到多行并使其更智能一点:
if not filename.startswith(".") \
and filename.lower().endswith(".exe") \
and not filename.endswith("-xyz.exe"):
#do stuff
请注意,这与*.eXe
,*.eXE
略有不同,然后扩展的其他混合大小写版本也将被忽略,与原始版本不同。但我敢打赌它不会真的重要,我的测试更好。
编辑:修复了".exe"
部分,因为我已经翻了条件,但如果你正在尝试学习正则表达式,这是一个奇怪的人为例子,我认为最好不要尝试和鞋拔正则表达式作为一个问题的解决方案,它不是一个好的解决方案
答案 3 :(得分:1)
你需要使用负面的lookbehind断言:
import re
regex = '[^.].*(?:(?<!-xyz).exe|.EXE)'
vectors = (
'.123.dat',
'.123.exe',
'.123.EXE',
'123.dat',
'123.exe',
'123.EXE',
'.123-xyz.dat',
'.123-xyz.exe',
'.123-xyz.EXE',
'123-xyz.dat',
'123-xyz.exe',
'123-xyz.EXE',
)
for v in vectors:
print "%s: " % (v,),
if (bool(re.match(regex, v)) == (not v.startswith(".") and
re.search("(.exe|.EXE)$", v) is not None and
not v.endswith("-xyz.exe"))):
print 'PASS'
else:
print 'FAIL'
答案 4 :(得分:1)
import re
pat = re.compile('(?!\.)'
'.+'
'\.'
'(?:(?<!-xyz\.)exe|EXE)'
'\Z')
names = ('.123.dat', '.123.exe', '.123.EXE',
'123.dat', '123.exe', '123.EXE',
'123-xyz.dat', '123-xyz.exe', '123-xyz.EXE', )
print '\n'.join(v.ljust(18)+str(bool(pat.match(v))) for v in names)
编辑:
你说得对,[^.]
优于(?!\.)
:它更具可读性,逻辑性更强,速度更快,-4%(我测试过)
我还比较了'(?!\.).+?\.(?:EXE|(?<!-xyz)exe)\Z'
(.+?
代替.+
)
使用此RE,执行时间更长。 额外的时间取决于测试名称中的点数。
在像'78999.abc.juty.123.dat'这样的名字上,它的长度大约增加了15%,在'123.dat'这样的名称上,这是3%更长的时间。 我认为原因是,如果读取的字符是一个点,则每次读取字符后正则表达式电机都会检查。
相反,使用'.+\.'
正则表达式电机一直运行到最后,然后返回搜索最后一个点。我认为这是一个正确的解释,因为如果RE '(?!\.).+?\.(?:EXE|(?<!-xyz)exe)\Z'
在'123.teybertyhbeythbeytberyetynetynetnyetnydat'等名称上进行测试,则时间再次更长(+ 30%)
我意识到我的RE与Ignacio的RE非常相似,我想知道为什么我写这个RE,因为它似乎没什么特别的兴趣。事实上,在开始时,我的想法是写'(?!\.).+?(?<=.EXE|(?<!-xyz).exe)\Z'
,然后我写了另一个字符串。顺便说一句,通过这个被放弃的RE,短名称的执行时间延长了25%,而长名称的执行时间延长了74%。
最后,当我测试执行时间时, Ignacio的解决方案在短名称('123.dat')上延长25%,在长名称上延长47%('78999.abc.juty.123.dat' )强>
最佳正则表达式
pat = re.compile('[^.]'
'.+'
'\.'
'(?:(?<!-xyz\.)exe|EXE)'
'\Z')
我允许'.+'
,而不是'.*'
替换,因为如果我们希望名称以'.exe'
或'.EXE'
结尾,则名称中必须至少包含4个字符
答案 5 :(得分:0)
这将涉及访问每个不以'。'开头的文件。或以'-xyz.exe'结尾。正则表达式模块无法解析其命名空间之外的内容。我不认为这是可能的,但您是否尝试过检查模块的文档?