我试图找出一个正则表达式,以匹配除特定组的最后一次出现之外的所有事件(即括号括起的公用名,如果存在)。遗憾的是,数据格式不是很好,但它不受我的控制。
这是预期输出->
预期输出
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)
之间。
答案 0 :(得分:2)
非正则表达式解决方案非常简单:
start, _, end = text.rpartition('(')
result = start or end
rpartition
将从结尾处搜索字符串,并在第一个(
处返回三元组(text-before, separator, text-after)
,在这种情况下separator = '('
。如果字符串中没有(...)
,则表示所有内容都在text-after
内,而text-before
和separator
都是空字符串。
当有(...)
时,您(
中的最后一个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)
^(?:(?!.*\(.*\)).*|.*(?= \(.*\)))
这个想法是你要匹配整行,括号内没有东西:
(?!.*\(.*\)).*
或直至最后一个空格的所有内容,后跟括号中的内容:
.*(?= \(.*\)
答案 2 :(得分:0)
你可以尝试一下
(.+)(?:\(.+\))$|(.+)
(.+)(?:\(.+\))$:
会在行尾找到包含单词的括号,并与之前的内容相匹配。
(.+):
匹配除换行符之外的所有字符。
然后捕获group 1
和group 2
<强>输出强>
Homo sapiens
mitochondrion Capra hircus
Escherichia coli
Xenopus (Silurana) tropicalis
请参阅DEMO