施工中
This commit is contained in:
parent
e44abbfdd2
commit
57684b9170
|
@ -0,0 +1,26 @@
|
|||
def solve_equation(eq):
|
||||
"""
|
||||
配平化学方程式,返回配平后的化学方程式
|
||||
|
||||
:param eq: 化学方程式,
|
||||
格式为
|
||||
{
|
||||
'left': [ {
|
||||
'atoms': [ {'元素名称': 元素个数}, {'元素名称': 元素个数}, ... ],
|
||||
'coefficient': 系数,
|
||||
'pretty_name': 化学式的字符串表示
|
||||
}, ... ],
|
||||
'right': [ ... ]
|
||||
}
|
||||
:return: 配平后的化学方程式,与输入格式相同
|
||||
若无法配平,则返回 None
|
||||
"""
|
||||
# 使用加减消元法解方程组
|
||||
# 依据:反应前后,每个元素的个数相等
|
||||
|
||||
# 用二维数组表示方程组的系数,用一维数组表示方程组的常数项
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
class Fraction:
|
||||
"""
|
||||
代表分数的类,包含分子和分母
|
||||
提供加减乘除运算
|
||||
"""
|
||||
def __init__(self, top, bottom):
|
||||
self.num = top
|
||||
self.den = bottom
|
||||
|
||||
def __str__(self):
|
||||
return str(self.num) + "/" + str(self.den)
|
||||
|
||||
def __add__(self, otherfraction):
|
||||
newnum = self.num * otherfraction.den + self.den * otherfraction.num
|
||||
newden = self.den * otherfraction.den
|
||||
return Fraction(newnum, newden)
|
||||
|
||||
def __sub__(self, otherfraction):
|
||||
newnum = self.num * otherfraction.den - self.den * otherfraction.num
|
||||
newden = self.den * otherfraction.den
|
||||
return Fraction(newnum, newden)
|
||||
|
||||
def __mul__(self, otherfraction):
|
||||
newnum = self.num * otherfraction.num
|
||||
newden = self.den * otherfraction.den
|
||||
return Fraction(newnum, newden)
|
||||
|
||||
def __truediv__(self, otherfraction):
|
||||
newnum = self.num * otherfraction.den
|
||||
newden = self.den * otherfraction.num
|
||||
return Fraction(newnum, newden)
|
||||
|
||||
def __eq__(self, otherfraction):
|
||||
firstnum = self.num * otherfraction.den
|
||||
secondnum = otherfraction.num * self.den
|
||||
return firstnum == secondnum
|
||||
|
||||
def __gt__(self, otherfraction):
|
||||
firstnum = self.num * otherfraction.den
|
||||
secondnum = otherfraction.num * self.den
|
||||
return firstnum > secondnum
|
||||
|
||||
def __lt__(self, otherfraction):
|
||||
firstnum = self.num * otherfraction.den
|
||||
secondnum = otherfraction.num * self.den
|
||||
return firstnum < secondnum
|
||||
|
||||
def __ge__(self, otherfraction):
|
||||
firstnum = self.num * otherfraction.den
|
||||
secondnum = otherfraction.num * self.den
|
||||
return firstnum >= secondnum
|
||||
|
||||
def __le__(self, otherfraction):
|
||||
firstnum = self.num * otherfraction.den
|
||||
secondnum = otherfraction.num * self.den
|
||||
return firstnum <= secondnum
|
||||
|
||||
def __ne__(self, otherfraction):
|
||||
firstnum = self.num * otherfraction.den
|
||||
secondnum = otherfraction.num * self.den
|
||||
return firstnum != secondnum
|
||||
|
||||
def get_num(self):
|
||||
return self.num
|
||||
|
||||
def get_den(self):
|
||||
return self.den
|
||||
|
||||
def __radd__(self, otherfraction):
|
||||
return self
|
||||
|
||||
|
||||
# 约分函数:将分数约分为最简分数
|
||||
def reduce_fraction(fraction):
|
||||
"""
|
||||
将分数约分为最简分数
|
||||
|
||||
:param fraction: 分数,Fraction 类型
|
||||
:return: 约分后的分数,Fraction 类型
|
||||
"""
|
||||
# 求最大公约数
|
||||
def gcd(a, b):
|
||||
if b == 0:
|
||||
return a
|
||||
else:
|
||||
return gcd(b, a % b)
|
||||
|
||||
g = gcd(fraction.get_num(), fraction.get_den())
|
||||
return Fraction(fraction.get_num() // g, fraction.get_den() // g)
|
||||
|
||||
|
||||
# 通分函数:将多个分数通分
|
||||
def common_denominator(fractions):
|
||||
"""
|
||||
将多个分数通分
|
||||
|
||||
:param fractions: 分数列表,Fraction 类型
|
||||
:return: 通分后的分数列表,Fraction 类型
|
||||
"""
|
||||
# 求最大公约数
|
||||
def gcd(a, b):
|
||||
if b == 0:
|
||||
return a
|
||||
else:
|
||||
return gcd(b, a % b)
|
||||
|
||||
# 求最小公倍数
|
||||
def lcm(a, b):
|
||||
return a * b // gcd(a, b)
|
||||
|
||||
# 通分
|
||||
denominator = 1
|
||||
for fraction in fractions:
|
||||
denominator = lcm(denominator, fraction.get_den())
|
||||
for i in range(len(fractions)):
|
||||
fractions[i] = Fraction(fractions[i].get_num() * denominator // fractions[i].get_den(), denominator)
|
||||
return fractions
|
|
@ -0,0 +1,17 @@
|
|||
# 这是一个示例 Python 脚本。
|
||||
|
||||
# 按 ⌃R 执行或将其替换为您的代码。
|
||||
# 按 双击 ⇧ 在所有地方搜索类、文件、工具窗口、操作和设置。
|
||||
|
||||
import parser
|
||||
from validity_check import IllegalAtomException
|
||||
|
||||
# 按间距中的绿色按钮以运行脚本。
|
||||
if __name__ == '__main__':
|
||||
eq = input('请输入化学方程式:')
|
||||
try:
|
||||
print(parser.parse_equation(eq))
|
||||
except IllegalAtomException as e:
|
||||
print(e.args[0])
|
||||
|
||||
# 访问 https://www.jetbrains.com/help/pycharm/ 获取 PyCharm 帮助
|
|
@ -0,0 +1,158 @@
|
|||
import re
|
||||
from validity_check import check_atom
|
||||
|
||||
|
||||
def parse_atom(atom):
|
||||
"""
|
||||
将化学式中的原子转化为字典
|
||||
:param atom: 原子的字符串表示
|
||||
:return: 原子的字典表示,{'元素名称': 元素个数}
|
||||
"""
|
||||
if len(atom) == 1:
|
||||
check_atom(atom)
|
||||
return {atom: 1}
|
||||
elif len(atom) == 2:
|
||||
if atom[1].isdigit():
|
||||
check_atom(atom[0])
|
||||
return {atom[0]: int(atom[1])}
|
||||
else:
|
||||
check_atom(atom)
|
||||
return {atom: 1}
|
||||
else:
|
||||
check_atom(atom[:-1])
|
||||
return {atom[:-1]: int(atom[-1])}
|
||||
|
||||
|
||||
def combine_same_atom(parsed_molecule):
|
||||
"""
|
||||
合并同类原子,类型不变,数量相加
|
||||
:param parsed_molecule: 化学式的字典表示
|
||||
:return: 合并完成后化学式的字典表示
|
||||
"""
|
||||
atoms = parsed_molecule['atoms']
|
||||
new_atoms = []
|
||||
for atom in atoms:
|
||||
for new_atom in new_atoms:
|
||||
if list(atom.keys())[0] == list(new_atom.keys())[0]:
|
||||
new_atom[list(atom.keys())[0]] += atom[list(atom.keys())[0]]
|
||||
break
|
||||
else:
|
||||
new_atoms.append(atom)
|
||||
return {
|
||||
'atoms': new_atoms,
|
||||
'coefficient': parsed_molecule['coefficient'],
|
||||
'pretty_name': parsed_molecule['pretty_name']
|
||||
}
|
||||
|
||||
|
||||
def parse_atomic_clusters(atomic_clusters):
|
||||
"""
|
||||
将原子团转化为字典
|
||||
:param atomic_clusters: 经过parse_molecule处理后的原子团
|
||||
如(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]
|
||||
elif atomic_clusters[-1] == ')':
|
||||
coefficient = 1
|
||||
else:
|
||||
raise ValueError('无效的原子团系数')
|
||||
# 解析原子团
|
||||
atoms = []
|
||||
for atom in atomic_clusters:
|
||||
atoms.append(parse_atom(atom))
|
||||
return {
|
||||
'atoms': atoms,
|
||||
'coefficient': coefficient,
|
||||
'pretty_name': ''.join(atomic_clusters)
|
||||
}
|
||||
|
||||
|
||||
def parse_molecule(molecule):
|
||||
"""
|
||||
将化学式转化为字典,以大小写区分不同元素(元素的第一个字母大写)
|
||||
注意一个化学式中可能包含多个元素
|
||||
应当得到一个字典:
|
||||
{
|
||||
'atoms': [ {'元素名称': 元素个数}, {'元素名称': 元素个数}, ... ],
|
||||
'coefficient': 系数,
|
||||
'pretty_name': 化学式的字符串表示
|
||||
}
|
||||
: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 = [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] != ')':
|
||||
j += 1
|
||||
if j == len(molecule):
|
||||
raise ValueError('括号不匹配')
|
||||
for k in range(i, j + 1):
|
||||
atomic_clusters.append(molecule[k])
|
||||
for k in range(i, j + 1):
|
||||
molecule[k] = ''
|
||||
# 如果出现单个数字,说明该数字是系数,将其追加到上一个原子/原子团(非空字符串)的后面
|
||||
if molecule[i].isdigit():
|
||||
while molecule[i - 1] == '':
|
||||
i -= 1
|
||||
if i == 0:
|
||||
raise ValueError('系数错误')
|
||||
molecule[i - 1] += molecule[i]
|
||||
molecule[i] = ''
|
||||
molecule = [i for i in molecule if i != '']
|
||||
atoms = []
|
||||
for i in molecule:
|
||||
atoms.append(parse_atom(i))
|
||||
# 解析原子团
|
||||
if len(atomic_clusters) != 0:
|
||||
parsed_atomic_clusters = parse_atomic_clusters(atomic_clusters)
|
||||
for each in parsed_atomic_clusters['atoms']:
|
||||
quantity = each[list(each.keys())[0]] * parsed_atomic_clusters['coefficient']
|
||||
each[list(each.keys())[0]] = quantity
|
||||
atoms.append(each)
|
||||
parsed_atom = {
|
||||
'atoms': atoms,
|
||||
'coefficient': coefficient,
|
||||
'pretty_name': pretty_name
|
||||
}
|
||||
return combine_same_atom(parsed_atom)
|
||||
|
||||
|
||||
def parse_equation(eq):
|
||||
"""
|
||||
将化学方程式转化为字典
|
||||
:param eq: 化学方程式
|
||||
:return: 化学方程式的字典表示
|
||||
"""
|
||||
eq = eq.replace(' ', '')
|
||||
eq = eq.replace('->', '=')
|
||||
eq = eq.replace('=', '=>')
|
||||
eq = eq.split('=>')
|
||||
left = eq[0]
|
||||
right = eq[1]
|
||||
left = left.split('+')
|
||||
right = right.split('+')
|
||||
left = [parse_molecule(molecule) for molecule in left]
|
||||
right = [parse_molecule(molecule) for molecule in right]
|
||||
return {
|
||||
'left': left,
|
||||
'right': right
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
# 目前已知的原子列表
|
||||
known_atoms = ['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', 'K',
|
||||
'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr',
|
||||
'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I',
|
||||
'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb',
|
||||
'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', 'Fr',
|
||||
'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', 'Rf',
|
||||
'Db', 'Sg', 'Bh', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', 'Nh', 'Fl', 'Mc', 'Lv', 'Ts', 'Og']
|
||||
|
||||
|
||||
class IllegalAtomException(Exception):
|
||||
"""
|
||||
元素名称不合法时引发的异常
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def check_atom(atom):
|
||||
"""
|
||||
判断元素名称是否合法
|
||||
:param atom: 元素名称
|
||||
:return: 无
|
||||
若不合法,抛出异常
|
||||
"""
|
||||
if atom not in known_atoms:
|
||||
raise IllegalAtomException('Illegal atom: {}'.format(atom))
|
Loading…
Reference in New Issue