首页 > 解决方案 > 如何从python中的字符串中检测正确的变量

问题描述

我正在尝试构建一个程序,该程序采用相当简单的化学公式并对其进行平衡。

假设一个例子是 Ca(Oh)₂ + HNO₃ → Ca(NO₃)₂ + H₂O

由于据我所知,没有办法在 python 中处理下标,我决定采用这种格式 Ca(Oh)_2 + HNO_3 = Ca(NO_3)_2 + H_2O,用 = 替换箭头,然后使用下划线作为下标。

到目前为止,我已经设法将等式的第一部分和第二部分分成单独的元素。所以我有清单

starters = ['Ca(Oh)_2', 'HNO_3']
products = ['Ca(NO_3)_2', 'H_2O']

这就是我卡住的地方。

我怎样才能遍历元素,并获得每个元素的数量。

我想把它存储在一个类似于

starter_amount = {element name; amount}
product_amount = {element name; amount}

理想情况下,它也会理解,例如 2NO_3,意味着有 2N 和 6 O

标签: pythonstringvariables

解决方案


这是一个相当复杂的问题,解决随机公式只是第一步。我希望以下功能对您有所帮助。它会解析您的随机公式以提取所有原子(顺便说一句:您应该在 Ca(OH)_2 中将 H 大写。否则,它将 Oh 视为一个元素。)。

使用此函数,您可以获得该产品或离析物中所有原子的列表。

def expand(stoch):
    f = ''
    for c in stoch:
        if c.isupper() or c == "(":
            f+=' '+c
        else:
            f+=c
    while '_' in f:
        i = f.rfind("_")
        if f[i-1]==")":
            l = 1
            start = i-2
            while l > 0:
                if f[start]=="(":
                    l-=1
                elif f[start]==")":
                    l+=1
                start-=1
            subform = f[start+2:i-1]
            subform = expand(subform)
            k = i+1
            while k<len(f):
                k+=1
                if not f[i+1:k].isdigit():break
            
            num = f[i+1:k]
            f = f[:start+1]+(subform+' ')*int(num)+f[k:]
            
        else:
            nc = 1
            subform = f[i-nc]
            while subform.islower():
                nc+=1
                subform = f[i-nc:i]

            k = i+1
            while k<len(f):
                k+=1
                if not f[i+1:k].isdigit():break
            
            num = f[i+1:k]
            f = f[:i-nc]+(subform+' ')*int(num)+f[k:]
    while '  ' in f: f = f.replace('  ',' ')  
    return f

该函数采用随机公式的语法,分解它并通过将每个元素乘以它应该的次数来简化 if。结果将是:

print(expand("Ca(OH)_2"))
print(expand("C_6H_12(OH)_2"))

## Ca O H O H 
## C C C C C C H H H H H H H H H H H H O H O H 

由于它是递归的,它将能够解析嵌套括号:

print(expand("Ca_3(C_3H_5(OH)_3)_2"))

## Ca Ca Ca C C C H H H H H O H O H O H C C C H H H H H O H O H O H 

如果您将其应用于您的问题,我建议创建一个区分 Product 和 Educt 并列出组件及其原子内容的字典,以便您稍后可以使用迭代程序访问它:

starters = ['Ca(OH)_2', 'HNO_3']
products = ['Ca(NO_3)_2', 'H_2O']

formula = {'Educts':[],'Products':[]}
for e in starters:
    atoms = expand(e).split(' ')
    while '' in atoms: atoms.remove('')
    formula['Educts'].append({'Formula':e,'Atoms':sorted(atoms)})
for p in products:
    atoms = expand(p).split(' ')
    while '' in atoms: atoms.remove('')
    formula['Products'].append({'Formula':p,'Atoms':sorted(atoms)})

for k,v in formula.items():
    print(k)
    for e in v:
        for k2,v2 in e.items():
            print('  - '+k2+': '+str(v2))
        print('')
 
## Output:
##
##Educts
##  - Formula: Ca(OH)_2
##  - Atoms: ['Ca', 'H', 'H', 'O', 'O']
##
##  - Formula: HNO_3
##  - Atoms: ['H', 'N', 'O', 'O', 'O']
##
##Products
##  - Formula: Ca(NO_3)_2
##  - Atoms: ['Ca', 'N', 'N', 'O', 'O', 'O', 'O', 'O', 'O']
##
##  - Formula: H_2O
##  - Atoms: ['H', 'H', 'O']

或者只是这个字典:{'Educts': [{'Formula': 'Ca(OH)_2', 'Atoms': ['Ca', 'O', 'H', 'O', 'H']}, {'Formula': 'HNO_3', 'Atoms': ['H', 'N', 'O', 'O', 'O']}], 'Products': [{'Formula': 'Ca(NO_3)_2', 'Atoms': ['Ca', 'N', 'O', 'O', 'O', 'N', 'O', 'O', 'O']}, {'Formula': 'H_2O', 'Atoms': ['H', 'H', 'O']}]}


推荐阅读