用户输入公式,例如:C12H2COOH
我们必须计算其分子量,假设C = 12.01,H = 1.008和O = 16。 我们被告知要小心它后面有两位数的元素和后面没有数字的元素。该程序还不断询问化学式,并在按下回车时退出。
我尝试过使用字典,for循环和while循环。我已经计算出像C2H2
这样的元素之后用单位数计算化合物,但是如果我把两位数放在元素旁边或者没有数字放在元素旁边,它就会失败。我还在研究如何在不删除分隔符的情况下分离字符串作为可能的路径?你们怎么解决这个问题?任何帮助将不胜感激,谢谢!
这是我到目前为止所拥有的。这太乱了。
xxx = ["H", "C", "O"]
elements = set(xxx)
while(True):
chemical_formula = input("Enter chemical formula, or enter to quit: ")
if chemical_formula == "":
break
else:
characters = list(chemical_formula)
n = 0
print(characters)
for i in characters:
if characters[n] == "C":
c = 12.0107
if elements.intersection(set(characters[n+1])):
print(c)
else:
number = int(characters[n+1])
print(number*c)
elif characters[n] == "H":
h = 1.00794
if elements.intersection(set(characters[n+1])):
print(h)
else:
number = int(characters[n+1])
print(number*h)
elif characters[n] == "O":
o = 15.9994
if elements.intersection(set(characters[n+1])):
print(c)
else:
number = int(characters[n+1])
print(number*o)
else:
numero = int(i)
print(i*0)
n = n+1
答案 0 :(得分:6)
我要做的第一件事是将输入字符串中每个字母替换为前面带有'+'的相同字母,所以
C12H2COOH => +C12+H2+C+O+O+H
接下来,我会用一个字母后跟一个字母后跟一个'*',然后用数字
替换每个字母后跟一个字母。+C12+H2+C+O+O+H => +C*12+H*2+C+O+O+H
然后我用它所代表的元素的分子量替换每个字母的出现
+C*12+H*2+C+O+O+H => +12.0107*12+1.00794*2+12.0107+15.9994+15.9994+1.00794
最后我会评估那个表达方式。我可以考虑使用2种或3种方法来执行这些修改,因为这是您的作业,如果它吸引您,我将让您选择如何实施此方法。但请注意,正则表达式后面的字符串操作后跟eval的邪恶并不是唯一的实现选项。
然后我开始研究如何处理缩写超过一个字母的元素。
答案 1 :(得分:4)
我整个夏天都在做12年级的化学课程,我也想过这样做。我想到了一种不同的方法,这里是版本1(' ZERO'只是一个地方持有人我只是没有用'')我检查了C12H2COOH和它给出了正确的答案(191.16克/摩尔)。希望这有助于某人:
__author__ = 'Elijah Lopez'
__version__ = 1.0
__created__ = '2017-08-07'
'''
Molar Mass Calculator - by Elijah Lopez
Version 1.0
Python 3.6
'''
MM_of_Elements = {'H': 1.00794, 'He': 4.002602, 'Li': 6.941, 'Be': 9.012182, 'B': 10.811, 'C': 12.0107, 'N': 14.0067,
'O': 15.9994, 'F': 18.9984032, 'Ne': 20.1797, 'Na': 22.98976928, 'Mg': 24.305, 'Al': 26.9815386,
'Si': 28.0855, 'P': 30.973762, 'S': 32.065, 'Cl': 35.453, 'Ar': 39.948, 'K': 39.0983, 'Ca': 40.078,
'Sc': 44.955912, 'Ti': 47.867, 'V': 50.9415, 'Cr': 51.9961, 'Mn': 54.938045,
'Fe': 55.845, 'Co': 58.933195, 'Ni': 58.6934, 'Cu': 63.546, 'Zn': 65.409, 'Ga': 69.723, 'Ge': 72.64,
'As': 74.9216, 'Se': 78.96, 'Br': 79.904, 'Kr': 83.798, 'Rb': 85.4678, 'Sr': 87.62, 'Y': 88.90585,
'Zr': 91.224, 'Nb': 92.90638, 'Mo': 95.94, 'Tc': 98.9063, 'Ru': 101.07, 'Rh': 102.9055, 'Pd': 106.42,
'Ag': 107.8682, 'Cd': 112.411, 'In': 114.818, 'Sn': 118.71, 'Sb': 121.760, 'Te': 127.6,
'I': 126.90447, 'Xe': 131.293, 'Cs': 132.9054519, 'Ba': 137.327, 'La': 138.90547, 'Ce': 140.116,
'Pr': 140.90465, 'Nd': 144.242, 'Pm': 146.9151, 'Sm': 150.36, 'Eu': 151.964, 'Gd': 157.25,
'Tb': 158.92535, 'Dy': 162.5, 'Ho': 164.93032, 'Er': 167.259, 'Tm': 168.93421, 'Yb': 173.04,
'Lu': 174.967, 'Hf': 178.49, 'Ta': 180.9479, 'W': 183.84, 'Re': 186.207, 'Os': 190.23, 'Ir': 192.217,
'Pt': 195.084, 'Au': 196.966569, 'Hg': 200.59, 'Tl': 204.3833, 'Pb': 207.2, 'Bi': 208.9804,
'Po': 208.9824, 'At': 209.9871, 'Rn': 222.0176, 'Fr': 223.0197, 'Ra': 226.0254, 'Ac': 227.0278,
'Th': 232.03806, 'Pa': 231.03588, 'U': 238.02891, 'Np': 237.0482, 'Pu': 244.0642, 'Am': 243.0614,
'Cm': 247.0703, 'Bk': 247.0703, 'Cf': 251.0796, 'Es': 252.0829, 'Fm': 257.0951, 'Md': 258.0951,
'No': 259.1009, 'Lr': 262, 'Rf': 267, 'Db': 268, 'Sg': 271, 'Bh': 270, 'Hs': 269, 'Mt': 278,
'Ds': 281, 'Rg': 281, 'Cn': 285, 'Nh': 284, 'Fl': 289, 'Mc': 289, 'Lv': 292, 'Ts': 294, 'Og': 294,
'ZERO': 0}
Compound = input('Molar Mass Caluclator \nExample: H2O not h2o \nEnter Compound Formula: ')
IsPolyatomic, End, Multiply = False, False, False
PolyatomicMass, MM, Multiplier = 0, 0, 1
Element = 'ZERO'
for i in range(0, len(Compound) + 1):
E = Compound[i:i + 1]
if IsPolyatomic:
if End:
IsPolyatomic = False
MM += int(E) * PolyatomicMass
elif E.isdigit():
if Multiply: Multiplier = int(str(Multiplier) + E)
else: Multiplier = int(E)
Multiply = True
elif E.islower(): Element += E
elif E.isupper():
PolyatomicMass += Multiplier * MM_of_Elements[Element]
Element, Multiplier, Multiply = E, 1, False
elif E == ')':
PolyatomicMass += Multiplier * MM_of_Elements[Element]
Element, Multiplier = 'ZERO', 1
End, Multiply = True, False
elif E == '(':
MM += Multiplier * MM_of_Elements[Element]
Element, Multiplier = 'ZERO', 1
IsPolyatomic, Multiply = True, False
elif E.isdigit():
if Multiply:
Multiplier = int(str(Multiplier) + E)
else: Multiplier = int(E)
Multiply = True
elif E.islower(): Element += E
elif E.isupper():
MM += Multiplier * MM_of_Elements[Element]
Element, Multiplier, Multiply = E, 1, False
elif i == len(Compound):
MM += Multiplier * MM_of_Elements[Element]
Element, Multiplier, Multiply = E, 1, False
print(f'The Molar mass of {Compound} is {round(MM)} g/mol')
答案 2 :(得分:3)
您的代码很乱,例如您不必要地将输入字符串转换为列表,然后迭代它,但仍然使用数字索引来访问字符。此外,在飞行中单独查看每个角色也没什么用处,因为这显然打破了多个数字的数字。另外,您可以单独输出每个遇到元素的权重 - 不应该输出总和吗?
以下代码使用小型状态机来解析输入字符串并输出组合权重。它假定每个公式都以一个元素开头,所有遇到的元素都包含在weights
字典中,并且没有元素名称比单个字符长:
#use a dictionary to map elements to their weights
weights = {"H": 1.00794, "C": 12.0107, "O": 15.9994}
def getInt(clist):
"""helper for parsing a list of chars as an int (returns 1 for empty list)"""
if not clist: return 1
return int(''.join(clist))
def getWeight(formula):
""" get the combined weight of the formula in the input string """
formula = list(formula)
#initialize the weight to zero, and a list as a buffer for numbers
weight = 0
num_buffer = []
#get the first element weight
el_weight = weights[formula.pop(0)]
while formula:
next = formula.pop(0)
if next in weights:
#next character is an element, add current element weight to total
weight += el_weight * getInt(num_buffer)
#get the new elements weight
el_weight = weights[element]
#clear the number buffer
num_buffer = []
else:
#next character is not an element -> it is a number, append to buffer
num_buffer.append(next)
#add the last element's weight and return the value
return weight + el_weight * getInt(num_buffer)
while 1:
#main loop
chemical_formula = input("Enter chemical formula, or enter to quit: ")
if not chemical_formula:
break
print("Combined weight is %s" % getWeight(chemical_formula))
这可以通过更改while
中getWeight
循环中的条件来轻松扩展以处理多字符元素,以便将字符附加到int缓冲区(如果它是一个数字),否则追加它到包含当前元素名称的字符串;然后,如果名称包含在''
字典中,则获取权重并将名称重置为weights
。
答案 3 :(得分:1)
这里是一个分子量python脚本,使用正则表达式来解析公式。
包含一些调试代码
import re
#some element data
elements ={}
elements["H"] = 1
elements["C"] = 12
elements["O"] = 16
elements["Cl"] = 35.45
#DDT (1,1,1-trichloro-2,2-di(4-chlorophenyl)ethane)
formula = "(ClC6H4)2CH(CCl3))"
sFormula = formula
print("Original Formula: ", sFormula)
#Search data inside ()
myRegEx = re.compile(r"(\()(\w*)(\))(\d*)",re.I)
myMatches = myRegEx.findall(sFormula)
while myMatches:
myMatches = myRegEx.findall(sFormula)
for match in myMatches:
print (match[1], match[3])
count = match[3]
text =""
if (count == ""):
count = 1
else:
count = int(match[3])
while (count >= 1):
text = text + match[1]
count -= 1
print(text)
sFormula = sFormula.replace('(' + match[1] + ')' + match[3], text)
print("Replaced formula: ",sFormula)
myRegEx = re.compile("(C[laroudsemf]?|Os?|N[eaibdpos]?|S[icernbmg]?|P[drmtboau]?|H[eofgas]?|A[lrsgutcm]|B[eraik]?|Dy|E[urs]|F[erm]?|G[aed]|I[nr]?|Kr?|L[iaur]|M[gnodt]|R[buhenaf]|T[icebmalh]|U|V|W|Xe|Yb?|Z[nr])(\d*)")
myMatches = myRegEx.findall(sFormula)
molecularFormula =""
MW = 0
text =""
for match in myMatches:
#Search symbol
symbol = match[0]
#Search numbers
number = match[1]
print(symbol,number)
if (number == ""):
number = 1
else:
number = int(match[1])
MW = MW + float(elements[symbol])*number
while (number >=1):
molecularFormula = molecularFormula + symbol
number -= 1
print(molecularFormula)
print("formula: " + formula + " MW = " + str(MW))
答案 4 :(得分:1)
首先:
pip install molmass
那么:
from molmass import Formula
Formula('H2O').isotope.mass
>> 18.01056468403 # monoisotopic mass
Formula('H2O').mass
>> 18.015287 # molecular mass