2012-03-20 20 views
5

पर आधारित सूची तत्वों में स्ट्रिंग स्ट्रिंग मैं एक फ़ंक्शन (पायथन में) बनाने की कोशिश कर रहा हूं जो इसके इनपुट (एक रासायनिक सूत्र) लेता है और एक सूची में विभाजित होता है। उदाहरण के लिए, यदि इनपुट "HC2H3O2" था, यह यह में बदल जाएगा:कीवर्ड

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

यह अब तक अच्छी तरह से काम, लेकिन अगर मैं इनपुट उस में दो पत्र, उदाहरण के लिए सोडियम के साथ एक तत्व (ना) , इसे में इसे विभाजित होगा:

['N', 'a'] 

मैं एक तरह से मेरी समारोह एक तत्व शब्दकोश बुलाया में पाया चाबी के लिए स्ट्रिंग के माध्यम से बनाने के लिए के लिए खोज कर रहा हूँ। मैं इसके लिए रेगेक्स का उपयोग करने पर भी विचार कर रहा हूं, लेकिन मुझे यकीन नहीं है कि इसे कैसे कार्यान्वित किया जाए। कैसे के बारे में

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

परिणाम

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

Regex समझाया

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

:

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 

यह अभिव्यक्ति है यह बाद से सुंदर गूंगा यह वही मेरी समारोह अभी है मनमाना "तत्व" स्वीकार करता है , "एक्सई" की तरह। आप की तरह Ba|Na|Mn...|C|O

बेशक तत्वों के नाम की वास्तविक सूची, | द्वारा अलग [A-Z][a-z]? भाग की जगह, द्वारा यह सुधार कर सकते हैं, नियमित अभिव्यक्ति केवल बहुत सरल सूत्रों संभाल कर सकते हैं,

8(NH4)3P4Mo12O40 + 64NaNO3 + 149NH4NO3 + 135H2O 
की तरह कुछ पार्स करने के लिए

आपको वास्तविक पार्सर की आवश्यकता होगी, उदाहरण के लिए pyparsing ("उदाहरण" के तहत "रासायनिक सूत्र" जांचना सुनिश्चित करें)। सौभाग्य!

+0

कि बढ़िया है, धन्यवाद! क्या आप रेगेक्स को समझाते हैं? – ohblahitsme

+0

'सीए (एचसीओओ) 2' के बारे में क्या? –

+0

+1 यह उल्लेख करने के लिए कि आपको रीगेक्स पार्सर की बजाय वास्तविक पार्सर की आवश्यकता होगी – aitchnyu

2

इस प्रकार की अभिव्यक्ति ब्याज के सभी भागों मिलान हो जाएगा:

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

आप इसे re.findall के साथ प्रयोग और फिर परमाणुओं कि कोई नहीं है के लिए परिमाणक जोड़ सकते हैं।

या आप के रूप में अच्छी है कि के लिए एक regex इस्तेमाल कर सकते हैं:

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

गैर regex दृष्टिकोण है, जो थोड़ा hackish शायद सबसे अच्छा नहीं है और है, लेकिन यह काम करता है:

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'] 
संबंधित मुद्दे