From e8404e1f9d91ac0b9638e94714f38993a60d4989 Mon Sep 17 00:00:00 2001 From: lucas8485 <1443937075@qq.com> Date: Sun, 11 Dec 2022 11:08:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BA=86parser=20=E7=9F=A9?= =?UTF-8?q?=E9=98=B5=E8=BF=90=E7=AE=97=E8=BF=98=E4=B8=8D=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- equation_solver.py | 21 ++++++++++++++------- main.py | 7 +++++-- parser.py | 37 ++++++++++++++++++++++++++++--------- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/equation_solver.py b/equation_solver.py index c1683f7..d990e5e 100644 --- a/equation_solver.py +++ b/equation_solver.py @@ -53,16 +53,22 @@ def solve_equation(eq): row.append(0) # 取出row中的最后一个元素,反转后加入常数项 constant.append(-row.pop()) + matrix.append(row) matrix = np.mat(matrix, int) - print(matrix) - print(constant) # 求解线性方程组 try: - result = sp.linalg.solve(matrix, constant).tolist() - except Exception as e: - print(e.args[0]) - print('无解') - return None + result = np.linalg.solve(matrix, constant).tolist() + except np.linalg.LinAlgError: + # 将常数项取负,插入到矩阵的最后一列 + constant = [-x for x in constant] + matrix = np.insert(matrix, matrix.shape[1], constant, axis=1) + # 再次尝试求解 + try: + constant = np.zeros(matrix.shape[0], int) + result = sp.linalg.solve(matrix, constant).tolist() + except Exception as e: + print('无法配平' + str(e)) + return None # 将结果写入化学方程式,最后一个生成物的系数需要计算得到 last_substance = eq['right'][-1] @@ -70,6 +76,7 @@ def solve_equation(eq): # 计算除最后一种生成物外的所有生成物包含last_atom的系数之和 sum_ = 0 index = 0 + print(result) for each in eq['left']: for atom in each['atoms']: if last_atom in atom: diff --git a/main.py b/main.py index 1e43525..0ce3fae 100644 --- a/main.py +++ b/main.py @@ -10,10 +10,13 @@ import equation_solver if __name__ == '__main__': while True: eq = input('请输入化学方程式:') + if eq == 'exit': + break try: eq = parser.parse_equation(eq) - equation_solver.solve_equation(eq) - print('化学方程式:', parser.format_equation(eq)) + eq = equation_solver.solve_equation(eq) + if eq is not None: + print('化学方程式:', parser.format_equation(eq)) except Exception as e: print(e.args[0]) diff --git a/parser.py b/parser.py index a2c2df5..b61f0de 100644 --- a/parser.py +++ b/parser.py @@ -49,21 +49,30 @@ def parse_atomic_clusters(atomic_clusters): """ 将原子团转化为字典 :param atomic_clusters: 经过parse_molecule处理后的原子团 - 如(ClO)2->['(', 'Cl', 'O', ')2'] + 如(ClO)2->['(', 'Cl', 'O', ')', '2'] :return: 原子团的字典表示 """ # 去除首括号 atomic_clusters = atomic_clusters[1:] # 去除尾括号,解析尾括号后的数值作为原子团系数 - if atomic_clusters[-1][-1].isdigit(): - coefficient = int(atomic_clusters[-1][-1]) - atomic_clusters = atomic_clusters[:-1] + if atomic_clusters[-1].isdigit(): + coefficient = int(atomic_clusters[-1]) + atomic_clusters = atomic_clusters[:-2] elif atomic_clusters[-1] == ')': coefficient = 1 else: raise ValueError('无效的原子团系数') # 解析原子团 atoms = [] + for i in range(len(atomic_clusters)): + if atomic_clusters[i].isdigit(): + while atomic_clusters[i - 1] == '': + i -= 1 + if i == 0: + raise ValueError('系数错误') + atomic_clusters[i - 1] += atomic_clusters[i] + atomic_clusters[i] = '' + atomic_clusters = [atom for atom in atomic_clusters if atom != ''] for atom in atomic_clusters: atoms.append(parse_atom(atom)) return { @@ -86,27 +95,30 @@ def parse_molecule(molecule): :param molecule: 化学式 :return: 化学式的字典表示 """ - pretty_name = '' if molecule[0].isdigit(): coefficient = int(molecule[0]) pretty_name = molecule = molecule[1:] else: coefficient = 1 pretty_name = molecule - # 以大写字母为分隔符,分割化学式 - molecule = re.split(r'([A-Z][a-z]*)', molecule) + # 以大写字母和括号为分隔符,分割化学式 + molecule = re.split('([A-Z][a-z]*|\(|\))', molecule) molecule = [i for i in molecule if i != ''] # 将原子团提取出来单独处理 atomic_clusters = [] for i in range(len(molecule)): if molecule[i] == '(': j = i + 1 - while molecule[j][0] != ')': + # 当molecule内不包含右括号 + while ')' not in molecule[j]: j += 1 if j == len(molecule): raise ValueError('括号不匹配') for k in range(i, j + 1): atomic_clusters.append(molecule[k]) + if j + 1 < len(molecule) and molecule[j + 1].isdigit(): + atomic_clusters.append(molecule[j + 1]) + molecule[j + 1] = '' for k in range(i, j + 1): molecule[k] = '' # 如果出现单个数字,说明该数字是系数,将其追加到上一个原子/原子团(非空字符串)的后面 @@ -169,6 +181,7 @@ def format_molecule(molecule): else: return molecule['pretty_name'] + def format_equation(eq): """ 将化学方程式的字典表示转化为字符串,需要包含系数 @@ -179,4 +192,10 @@ def format_equation(eq): right = eq['right'] left = [format_molecule(molecule) for molecule in left] right = [format_molecule(molecule) for molecule in right] - return ' + '.join(left) + ' => ' + ' + '.join(right) \ No newline at end of file + return ' + '.join(left) + ' => ' + ' + '.join(right) + + +if __name__ == '__main__': + eq = input('测试parser:请输入分子式:') + parsed_eq = parse_molecule(eq) + print('解析结果:', parsed_eq)