拆分带分隔符和条件的字符串

时间:2016-03-01 06:27:14

标签: python regex string split lookahead

我试图分割由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))这样的东西。非常感谢任何帮助。

3 个答案:

答案 0 :(得分:0)

使用单个正则表达式处理分割字符串似乎过于复杂。分别处理(+ M)的特殊情况会更容易:

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

答案 1 :(得分:0)

所以这是你正在寻找的正则表达式。

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

使用的标志:

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

<强>解释

  • ((?=\(\+)\()检查(是否存在(+。这涵盖了(+M)问题的第一部分。

  • 如果((?<=M)\))前面有)
  • M会检查是否存在)。这涵盖了(+M)问题的第二部分。

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

注意: digits()断言确保positive lookahead包围positive lookbehind

Check Regex101 demo for working

P.S:让它适合自己,因为我还不是python程序员。

答案 2 :(得分:0)

您可以改为使用 re.findall()

  

re.findall(pattern,string,flags = 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 的模式与 split 的模式不同, 因为 findall 拆分正在寻找不同的东西; '相反的事情',确实。

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

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

findall ,' [A-Z0-9] +(?:([1-9],[1-9]))?' 匹配任何大写或数字&gt;的 [A-Z0-9] 下, 一次或多次&gt; + 跟随一对数字,中间有逗号,括号内&gt;的 \([1-9],[1-9] \) (字符类之外的字面括号必须使用反斜杠'\'进行转义),可选&gt;的

\([1-9],[1-9] \)位于(?:)内,然后, (使其成为可选项); (),而不是(?:),但在这种情况下,(?:)更好; (?:)是一个无捕获组:请阅读此内容。

使用拆分

中的正则表达式进行尝试