2013-08-24 33 views
3

我有一個正則表達式,其可具有無論是從表達:蟒重,發現含有可選的組

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

發生更長的串內的這些表達式(它們不是單獨的字符串)。我在使用re.searchre.findall時遇到了匹配兩個表達式的問題(因爲字符串中可能有多個表達式)。

它的簡單,足以匹配單獨,但我怎麼能去,使返回兩組匹配任何一種情況下,先用src://path/...和第二,如果它存在的optional stringNone如果不是?

我想,我需要以某種指定或羣體---比如,可以考慮:

\((.*)(".*")\)第二個實例,但不是第一個,因爲它不包含"..."匹配模式。

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) 

任何想法,你們的表達(常規品種)的主人?

回答

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', '')] 
+0

+1非貪婪捕捉是要走的路。 – javadba

2

由於"通常不會允許出現在文件名,你可以簡單地從第一組中排除:

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

這通常是the preferred alternative to ungreedy repetition,因爲往往會更有效率。如果你的文件名可以出於某種原因實際包含引號,那麼不確定的重複(如agf的答案)是最好的選擇。

+0

感謝您提供有效率的備選方案。我發現這種方法快8倍左右,但有注意事項。 – BFTM

+0

@BFTM你的意思是什麼?從某種意義上說,你的文件名包含'「'? –

+0

是的,第一個表達式不能包含'」的警告。在上面的情況下,這是一個很好的解決方案,因爲文件名不會包含''',但非貪婪搜索似乎更普遍(但更慢)。 – BFTM