2016-03-01 45 views
0

我试图拆分由whitespace, +, =定界的化学反应的一般字符串,其中可能有任意数量的空格。这是一般情况,但我也需要它在()内发现+时,有条件地在括号字符()上分割。用分隔符和条件拆分字符串

例如:

reaction= 'C5H6 + O = NC4H5 + CO + H' 

应拆分,使得结果是

 splitresult=['C5H6','O','NC4H5','CO','H'] 

此情况下,使用时filter(None,re.split('[\s+=]',reaction))似乎简单。但现在有条件分裂。一些反应将有一个(+M),我也想分开,只留下M。在这种情况下,总会有一个+M括号

内部。例如:

reaction='C5H5 + H (+M)= C5H6 (+M)' 
    splitresult=['C5H5','H','M','C5H6','M'] 

然而,会有一些情况下,括号不会分隔符。在这些情况下,不会有+M,但其他的东西并不重要。

例如:

reaction='C5H5 + HO2 = C5H5O(2,4) + OH' 
    splitresult=['C5H5','HO2','C5H5O(2,4)','OH'] 

我最好的猜测是使用负前瞻和回顾后,以匹配+M,但我不知道如何把到这一点我上面使用了简单的情况下,正则表达式表达。我的直觉是使用类似filter(None,re.split('[(?<=M)\)\((?=\+)=+\s]',reaction))。任何帮助深表感谢。

回答

0

你可以使用re.findall()代替:

re.findall(图案,字符串标志= 0) 返回图案的所有非重叠 匹配字符串中,作为一个字符串列表。该字符串是从左到右扫描的 ,匹配按找到的顺序返回。如果 模式中存在一个或多个组,则返回 组的列表;如果该模式具有多个 组,则这将是元组列表。除非他们触及另一场比赛的开始 ,否则结果中会包含空符。

则:

import re 
reaction0= 'C5H6 + O = NC4H5 + CO + H' 
reaction1='C5H5 + H (+M)= C5H6 (+M)' 
reaction2='C5H5 + HO2 = C5H5O(2,4) + OH' 
re.findall('[A-Z0-9]+(?:\([1-9],[1-9]\))?',reaction0) 
re.findall('[A-Z0-9]+(?:\([1-9],[1-9]\))?',reaction1) 
re.findall('[A-Z0-9]+(?:\([1-9],[1-9]\))?',reaction2) 

但是,如果你喜欢re.split()滤波器(),则:

import re 
reaction0= 'C5H6 + O = NC4H5 + CO + H' 
reaction1='C5H5 + H (+M)= C5H6 (+M)' 
reaction2='C5H5 + HO2 = C5H5O(2,4) + OH' 
filter(None , re.split('(?<!,[1-9])[\s+=()]+(?![1-9,])',reaction0)) 
filter(None , re.split('(?<!,[1-9])[\s+=()]+(?![1-9,])',reaction1)) 
filter(None , re.split('(?<!,[1-9])[\s+=()]+(?![1-9,])',reaction2)) 

模式为findall是从不同的模式拆分, 因为findall拆分正在寻找不同的东西; '相反的东西'的确如此。

findall,正在寻找你想要的(保持它)。

拆分,正在寻找你不想(摆脱它)。

findall,'[A-Z0-9] +(?:((1-9),[1-9]))?' 匹配任何大写或数>[A-Z0-9]一次或多次>+后续由一对数字,在中间一逗号,内括号的>\([1-9],[1-9] \) (字符类以外字面括号,必须用反斜杠转义 '\'),任选>

\([1-9],[1-9] \)内部(?:),然后, 的(使其可选); (),而不是(?:)的作品,但在这种情况下,(?:)更好; (?:)是一个没有捕获组:阅读关于这个。

尝试与在正则表达式拆分

+0

我没有固有的理由使用'findall'作为'split'。这正是首先想到的。我对正则表达式不是很熟悉,你能否详细说明你的模式匹配的方式(它如何捕捉'()')以及为''findall''split'使用不同的模式? – smbio

+0

现在看看答案 –

+0

完美。谢谢。 – smbio

0

这似乎过于复杂,处理与单个正则表达式分裂字符串。这将会是很容易分开处理的(+ M)的特殊情况:

halfway = re.sub("\(\+M\)", "M", reaction) 
result = filter(None, re.split('[\s+=]', halfway)) 
0

因此,这里是你正在寻找的正则表达式。

正则表达式:使用((?=\(\+)\()|[\s+=]|((?<=M)\))

标志:

  • g全局搜索。或根据您的情况使用它们。

说明:

  • ((?=\(\+)\()检查一个(其存在如果(+存在。这涵盖了您的(+M)问题的第一部分。

  • ((?<=M)\))检查一个)如果M)之前,其存在。这涵盖了您的(+M)问题的第二部分。

  • [\s+=]检查所有剩余的whitespaces,+=。这涵盖了问题的最后部分。

注:digits照顾被()双方positive lookaheadpositive lookbehind断言确保封闭。

Check Regex101 demo for working

P.S:让它适合自己,因为我不是一个Python程序员呢。

+0

问题与您正则表达式按照我的理解是'|'操作。我相信它是非贪婪的,这意味着它只会匹配其中一种模式,然后退出。我需要它来检查整个字符串并匹配模式的每个实例,而不仅仅是一个。 – smbio

+0

我已经使用全局搜索模式'g'。即使它们在退出之前被'|'分开,它也会找到每个模式。 – 2016-03-01 14:28:10