排除文本的最后匹配部分

时间:2015-09-28 13:32:45

标签: python regex python-2.7

我试图找出一个正则表达式,以匹配除特定组的最后一次出现之外的所有事件(即括号括起的公用名,如果存在)。遗憾的是,数据格式不是很好,但它不受我的控制。

这是预期输出->预期输出

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

我尝试了一个积极的前瞻,但它在 case 3 上失败了,因为没有给出通用名称。尝试匹配([^()]*)和捕获组0 并不适用于案例4 ,并且我对尝试拼接匹配的群组持谨慎态度因为我不能保证括号括起来的科学名称[即'(Silurana)']将介于 genus (Xenopus) (tropicalis)之间。

3 个答案:

答案 0 :(得分:2)

非正则表达式解决方案非常简单:

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

rpartition将从结尾处搜索字符串,并在第一个(处返回三元组(text-before, separator, text-after),在这种情况下separator = '('。如果字符串中没有(...),则表示所有内容都在text-after内,而text-beforeseparator都是空字符串。 当有(...)时,您(中的最后一个text-before之前的所有文字都有(text-after...)将{ {1}}。

因此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

这个想法是你要匹配整行,括号内没有东西:

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

或直至最后一个空格的所有内容,后跟括号中的内容:

.*(?= \(.*\)

答案 2 :(得分:0)

你可以尝试一下

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

(.+)(?:\(.+\))$: 会在行尾找到包含单词的括号,并与之前的内容相匹配。

(.+): 匹配除换行符之外的所有字符。

然后捕获group 1group 2

<强>输出

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

请参阅DEMO