2012-03-20 11 views
5

Girişini (bir kimyasal formül) alan ve bir listeye bölen bir işlev (Python'da) oluşturmaya çalışıyorum. giriş "HC2H3O2" ise Örneğin, bu çevirmek olacaktır:Anahtar kelimeleri temel alan liste öğelerine ayırın

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

Bu, şimdiye kadar iyi çalışır, ancak girdi eğer örneğin sodyum içinde iki harf, bir eleman (Na) benim işlevi bir sözlük denilen elemanlar bulunan tuşlar için dize yoluyla görünmesi için bir yol arıyorum

['N', 'a'] 

: bu bölün olacaktır. Bunun için regex kullanmayı da düşünüyorum, ancak bunu nasıl uygulayacağımı bilmiyorum.

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 

cevap

4

yaklaşık

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

sonuç

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

Regex açıkladı Nasıl:

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 

Bu ifade edilir bunun beri oldukça aptal Bu benim işlevi şu anda budur keyfi "elementleri" kabul eder "Xy" gibi. Sen, düzenli ifadeler sadece

8(NH4)3P4Mo12O40 + 64NaNO3 + 149NH4NO3 + 135H2O 
gibi bir şey ayrıştırmak için, çok basit formüller işleyebilir Tabii Ba|Na|Mn...|C|O

gibi | ile ayrılan elemanların isimleri fiili listesi ile [A-Z][a-z]? bölümünü değiştirerek bunu artırabilir

gerçek bir ayrıştırıcıya ihtiyacınız olacak, örneğin pyparsing ("Örnekler" altındaki "kimyasal formülleri" kontrol ettiğinizden emin olun). İyi şanslar!

+0

parlak Yani, teşekkür ederim! Normal ifadeyi açıklar mısınız? – ohblahitsme

+0

Ya Ca (HCOO) 2' hakkında? Bir regex ayrıştırıcısı yerine gerçek bir ayrıştırıcıya ihtiyacınız olduğunu belirtmek için –

+0

+1 – aitchnyu

2

böyle bir ifade çıkar tüm parçaları eşleşir:

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

Sen re.findall ile kullanmak ve daha sonra hiç yok atomlar için niceleyici ekleyebilir.

Yoksa bunun için de bir regex kullanabilirsiniz:

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

Çıktı:

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

sub izleyen bir sayı değil bütün atomların sonra 1 ekler.

0

muhtemelen iyi biraz hackish ve olmayan regex yaklaşım, ama çalışıyor:

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'] 
İlgili konular