2012-03-20 26 views
5

Tôi đang cố tạo hàm (bằng Python) lấy đầu vào của nó (công thức hóa học) và tách thành một danh sách. Ví dụ, nếu đầu vào là "HC2H3O2", nó sẽ biến nó thành:Tách chuỗi thành các phần tử danh sách dựa trên từ khóa

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

này, hoạt động tốt cho đến nay, nhưng nếu tôi nhập vào một phần tử với hai chữ cái trong nó, ví dụ natri (Na) , nó sẽ chia thành:

['N', 'a'] 

Tôi đang tìm cách để thực hiện chức năng của mình thông qua chuỗi khóa tìm thấy trong từ điển được gọi là phần tử. Tôi cũng đang xem xét sử dụng regex cho điều này, nhưng tôi không chắc chắn làm thế nào để thực hiện nó. Đây là những gì chức năng của tôi là ngay bây giờ:

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 

Trả lời

4

Làm thế nào về

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

kết quả

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

Regex giải thích:

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 

biểu hiện này được khá ngớ ngẩn vì nó chấp nhận "yếu tố" tùy ý , như "Xy". Bạn có thể cải thiện nó bằng cách thay thế một phần [A-Z][a-z]? với danh sách thực tế của tên các yếu tố, được phân tách bởi |, như Ba|Na|Mn...|C|O

Tất nhiên, biểu thức thông thường chỉ có thể xử lý các công thức rất đơn giản, để phân tích cái gì đó như

8(NH4)3P4Mo12O40 + 64NaNO3 + 149NH4NO3 + 135H2O 

bạn sẽ cần một trình phân tích cú pháp thực, ví dụ pyparsing (đảm bảo kiểm tra "công thức hóa học" trong "Ví dụ"). Chúc may mắn!

+0

Đó là rực rỡ, cảm ơn bạn! Bạn có thể giải thích về regex không? – ohblahitsme

+0

Còn về 'Ca (HCOO) 2' thì sao? –

+0

+1 để đề cập rằng bạn sẽ cần một trình phân tích cú pháp thực, thay vì một trình phân tích cú pháp regex – aitchnyu

2

Một biểu hiện như thế này sẽ phù hợp với tất cả các phần quan tâm:

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

Bạn có thể sử dụng nó với re.findall và sau đó thêm lượng hóa cho các nguyên tử có ai sánh kịp.

Hoặc bạn có thể sử dụng một regex cho rằng là tốt:

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

Output:

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

Các sub thêm một 1 sau khi tất cả các nguyên tử không theo sau là một số.

0

Cách tiếp cận phi regex, mà là một chút hackish và có lẽ không phải là tốt nhất, nhưng nó hoạt động:

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'] 
Các vấn đề liên quan