2015-09-28 32 views
0

我想找出一個正則表達式來匹配除特定組的最後一次出現(即括號括起來的常用名,如果存在)以外的所有正則表達式。可悲的是,這些數據格式不是特別好,但它超出了我的控制範圍。排除文本的最後一個匹配部分

這裏的預期輸入->預期輸出

Homo sapiens (human) -> Homo sapiens 
mitochondrion Capra hircus (goat) -> mitochondrion Capra hircus 
Escherichia coli -> Escherichia coli 
Xenopus (Silurana) tropicalis (western tree frog) -> Xenopus (Silurana) tropicalis 

我嘗試了正向前查找,但未能對情況下3因爲沒有給出通用名稱。試圖匹配([^()]*)和捕獲組0不適用於案例4,並且我非常謹慎地嘗試將匹配的組拼接在一起,因爲我不能保證括號中包含的學名[即'(Silurana)']將落入(Xenopus)物種(tropicalis)

+0

必須解決的一個正則表達式來實現?做一次「足夠接近」的比賽通常會更容易,然後做一些進一步的處理,比如在比賽結束時剝去括號內的任何東西。 –

+0

@BryanOakley,如果我理解正確,根據第三個例子,它應該匹配。 – ndn

+0

@ndn:謝謝。我不知何故錯過了看第三個例子。我已更新我的評論。 –

回答

2

非正則表達式解決方案是相當平凡的:

start, _, end = text.rpartition('(') 
result = start or end 

rpartition將結束搜索的字符串,並在第一(返回三重(text-before, separator, text-after)其中separator = '('在這種情況下。如果字符串中沒有(...),則說明所有內容都在text-after之內,並且text-beforeseparator都是空字符串。 當出現(...)時,您將在text-before的最後一個(之前獲得所有文本,分隔符爲(text-after將爲...)

因此start or end總是包含您需要的值。如果start不是你想要的,否則結果在end

或者:

result = next(filter(None, text.rpartition('('))) 

樣品運行:

In [1]: texts = [ 
    ...:  'Homo sapiens (human)', 
    ...:  'mitochondrion Capra hircus (goat)', 
    ...:  'Escherichia coli', 
    ...:  'Xenopus (Silurana) tropicalis (western tree frog)', 
    ...: ] 

In [2]: for text in texts: 
    ...:  start, _, end = text.rpartition('(') 
    ...:  print('in {!r}\t->\t{!r}'.format(text, start or end)) 
    ...:  
in 'Homo sapiens (human)'  ->  'Homo sapiens ' 
in 'mitochondrion Capra hircus (goat)' ->  'mitochondrion Capra hircus ' 
in 'Escherichia coli' ->  'Escherichia coli' 
in 'Xenopus (Silurana) tropicalis (western tree frog)' ->  'Xenopus (Silurana) tropicalis ' 

In [3]: for text in texts: 
    ...:  print('in {!r}\t->\t{!r}'.format(text, next(filter(None, text.rpartition('('))))) 
in 'Homo sapiens (human)'  ->  'Homo sapiens ' 
in 'mitochondrion Capra hircus (goat)' ->  'mitochondrion Capra hircus ' 
in 'Escherichia coli' ->  'Escherichia coli' 
in 'Xenopus (Silurana) tropicalis (western tree frog)' ->  'Xenopus (Silurana) tropicalis ' 

時序:

In [13]: texts *= 1000 

In [14]: %%timeit 
    ...: results = [] 
    ...: for text in texts: 
    ...:  start, _, end = text.rpartition('(') 
    ...:  results.append(start or end) 
    ...: 
1000 loops, best of 3: 1.04 ms per loop 

其比基於正則表達式的溶液快4倍以上:

In [15]: import re 

In [16]: %%timeit regex = re.compile(r'^(?:(?!.*\(.*\)).*|.*(?= \(.*\)))') 
    ...: results = [] 
    ...: for text in texts: 
    ...:  match = regex.match(text) 
    ...:  results.append(match.group(0)) 
    ...: 
100 loops, best of 3: 4.27 ms per loop 

filter版本比or解決方案稍慢:

In [19]: %%timeit 
    ...: results = [] 
    ...: for text in texts: 
    ...:  results.append(next(filter(None, text.rpartition('(')))) 
    ...: 
1000 loops, best of 3: 1.89 ms per loop 
+1

我總是比正則表達式更喜歡幾行代碼。正則表達式是完全不可讀的,除非你每天都在使用它。而且這個代碼比正則表達式更快的事實就是錦上添花。不錯的工作! –

1
^(?:(?!.*\(.*\)).*|.*(?= \(.*\))) 

See it in action

的想法是,要匹配或者整條生產線,其中沒有括號的東西:

(?!.*\(.*\)).* 

或一切,直到最後空間,其次是在括號內的東西:

.*(?= \(.*\) 
+0

@Downvoter你能解釋一下嗎? – ndn

0

你可以試試這個出

(.+)(?:\(.+\))$|(.+) 

(.+)(?:\(.+\))$:在該行的末尾查找括號文字和匹配什麼在它之前。

(.+):匹配除換行符以外的任何字符。

然後捕獲group 1group 2

輸出

Homo sapiens 
mitochondrion Capra hircus 
Escherichia coli 
Xenopus (Silurana) tropicalis 

DEMO

+0

好方法。儘管它將「埃希氏菌」和「大腸桿菌」作爲單獨的匹配。使用'(。+)'代替第二次交替。 – Mariano

+0

感謝馬里亞諾編輯 –

相關問題