2012-03-20 3 views
5

入力(化学式)を受け取り、リストに分割する関数(Pythonで)を作成しようとしています。 入力が「HC2H3O2」だった場合、それはにそれを回すでしょう:キーワードを基にリスト要素に文字列を区切ります

molecule_list = ['H', 1, 'C', 2, 'H', 3, 'O', 2] 

これ、今のところうまく動作しますが、たとえば、ナトリウム(Na)のために、それに2つの文字、とI入力要素を場合

要素という辞書にあるキーの文字列を見るための方法を探しています。私はまた、正規表現を使用して検討しているが、私はそれを実装する方法がわからない。これは私の関数は、今あるものである:

def split_molecule(inputted_molecule): 
    """Take the input and split it into a list 
    eg: C02 => ['C', 1, 'O', 2] 
    """ 
    # step 1: convert inputted_molecule to a list 
    # step 2a: if there are two periodic elements next to each other, insert a '1' 
    # step 2b: if the last element is an element, append a '1' 
    # step 3: convert all numbers in list to ints 

    # step 1: 
    # problem: it splits Na into 'N', 'a' 
    # it needs to split by periodic elements 
    molecule_list = list(inputted_molecule) 

    # because at most, the list can double when "1" is inserted 
    max_length_of_molecule_list = 2*len(molecule_list) 
    # step 2a: 
    for i in range(0, max_length_of_molecule_list): 
     try: 
      if (molecule_list[i] in elements) and (molecule_list[i+1] in elements): 
       molecule_list.insert(i+1, "1") 
     except IndexError: 
      break 
    # step2b:  
    if (molecule_list[-1] in elements): 
     molecule_list.append("1") 

    # step 3: 
    for i in range(0, len(molecule_list)): 
     if molecule_list[i].isdigit(): 
      molecule_list[i] = int(molecule_list[i]) 

    return molecule_list 

答えて

4

正規表現について説明いかが

import re 
print re.findall('[A-Z][a-z]?|[0-9]+', 'Na2SO4MnO4') 

結果

['Na', '2', 'S', 'O', '4', 'Mn', 'O', '4'] 

Find everything that is either 

    [A-Z] # A,B,...Z, ie. an uppercase letter 
    [a-z] # followed by a,b,...z, ie. a lowercase latter 
    ?  # which is optional 
    |  # or 
    [0-9] # 0,1,2...9, ie a digit 
    +  # and perhaps some more of them 

をこの式は、それ以来、かなり間抜けです任意の "要素"を受け入れる、 "Xy"のように。あなたは、正規表現のみ

8(NH4)3P4Mo12O40 + 64NaNO3 + 149NH4NO3 + 135H2O 
ようなものを解析するために、非常に単純な数式を扱うことができる。もちろん、 Ba|Na|Mn...|C|O

のように、|で区切られた要素の名前の実際のリスト、と[A-Z][a-z]?一部を置き換えることによって、それを改善することができます

あなたは本当のパーサを必要とします。 pyparsing(「化学式」の「例」を確認してください)。がんばろう!

+0

華麗です、ありがとう!あなたは正規表現を説明してもらえますか? – ohblahitsme

+0

'Ca(HCOO)2'はどうですか? –

+0

+1正規表現パーサーではなく、実際のパーサーが必要であると言及しています – aitchnyu

2

このような表現は、関心のあるすべての部分と一致します:

[A-Z][a-z]*|\d+ 

あなたはre.findallでそれを使用して、どれを持っていない原子のために数量詞を追加することができます。

それともあなたにも、そのために正規表現を使用することができます。

molecule = 'NaHC2H3O2' 
print re.findall(r'[A-Z][a-z]*|\d+', re.sub('[A-Z][a-z]*(?![\da-z])', r'\g<0>1', molecule)) 

出力:

['Na', '1', 'H', '1', 'C', '2', 'H', '3', 'O', '2'] 

subは番号が付いていないすべての原子後1を追加します。

0

ビットハックで、おそらくない最高の、それは働く非正規表現のアプローチは、:

import string 

formula = 'HC2H3O2Na' 
m_list = list() 
for x in formula: 
    if x in string.lowercase: 
     m_list.append(formula[formula.index(x)-1]+x) 
     _ = m_list.pop(len(m_list)-2) 
    else: 
     m_list.append(x) 
print m_list 
['H', 'C', '2', 'H', '3', 'O', '2', 'Na'] 
関連する問題