python re,查找包含可选组的表达式

时间:2013-08-24 15:29:09

标签: python regex

我有一个正则表达式,可以来自:

(src://path/to/foldernames canhave spaces/file.xzy)
(src://path/to/foldernames canhave spaces/file.xzy "optional string")

这些表达式出现在一个更长的字符串中(它们不是单独的字符串)。在使用re.searchre.findall时,我无法匹配两个表达式(因为字符串中可能有多个表达式)。

它足够简单,可以单独匹配,但如何匹配任何一种情况,以便返回两个组,第一组返回src://path/...,第二组返回optional string存在或None如果不存在?

我在想我需要以某种方式指定OR组 - 例如,考虑:

模式\((.*)( ".*")\)匹配第二个实例,但不匹配第一个实例,因为它不包含"..."

r = re.search(r'\((.*)( ".*")\)', '(src://path/to/foldernames canhave spaces/file.xzy)'
r.groups()  # Nothing found
AttributeError: 'NoneType' object has no attribute 'groups'

虽然\((.*)( ".*")?\)与第一个组匹配,但在第二个实例中没有单独将"optional string"标识为一个组。

r = re.search(r'\((.*)( ".*")?\)', '(src://path/to/foldernames canhave spaces/file.xzy "optional string")')
r.groups()
('src://path/to/foldernames canhave spaces/file.xzy "optional string"', None)

任何想法,你们'表达的主人(常规品种)?

2 个答案:

答案 0 :(得分:4)

最简单的方法是制作第一个* non-greedy

>>> import re
>>> string = "(src://path/to/foldernames canhave spaces/file.xzy)"
>>> string2 = \
... '(src://path/to/foldernames canhave spaces/file.xzy "optional string")'
>>> re.findall(r'\((.*?)( ".*")?\)', string2)
[('src://path/to/foldernames canhave spaces/file.xzy', ' "optional string"')]
>>> re.findall(r'\((.*?)( ".*")?\)', string)
[('src://path/to/foldernames canhave spaces/file.xzy', '')]

答案 1 :(得分:2)

由于"通常不允许出现在文件名中,因此您只需将其从第一组中排除即可:

r = re.search(r'\(([^"]*)( ".*")?\)', input)

这通常是the preferred alternative to ungreedy repetition,因为往往效率更高。如果您的文件名由于某种原因实际上可以包含引号,那么不合理的重复(如agf的答案中)是您最好的选择。