2016-03-01 133 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