
本文介绍如何用纯 Python(不依赖第三方库)将化学式如 Al2(SO4)3 解析为嵌套元组结构,精确分离元素符号与系数,并支持括号嵌套与数量展开,为后续化学方程式配平奠定基础。
本文介绍如何用纯 python(不依赖第三方库)将化学式如 `al2(so4)3` 解析为嵌套元组结构,精确分离元素符号与系数,并支持括号嵌套与数量展开,为后续化学方程式配平奠定基础。
化学式的结构具有天然的递归性:原子可带下标(如 O2),括号内可嵌套子式并整体带系数(如 (SO4)3),甚至多层嵌套(如 Ca(OH)2 或 K3[Fe(CN)6])。正则表达式本质上是线性匹配工具,无法处理任意深度的括号嵌套与上下文相关的数量分配,因此仅靠 regex 无法可靠完成该任务——这是计算理论中的经典限制(正则语言无法识别平衡括号语言)。
正确的解决路径是:先用正则粗粒度切分,再用递归下降解析器逐层展开。下面提供一个轻量、可读性强、无外部依赖的实现方案:
✅ 核心思路
- 外层切分:用正则识别“独立单元”——即单个元素(Al2)、带括号的子式((SO4)3)或裸括号内容(需进一步处理);
- 递归解析:对每个单元,若以 ( 开头,则递归解析括号内部分,并乘以其后的系数;否则按 元素+数字 模式解析;
- 统一归一化:空系数默认为 1,数字字符串转为 int,最终返回嵌套元组结构,便于后续遍历与展开。
? 完整可运行代码
import re
def parse_formula(segment):
"""解析不含括号的原子段,如 'Al2', 'S', 'O4' → [('Al', 2), ('S', 1), ('O', 4)]"""
matches = re.findall(r'([A-Z][a-z]*)(\d*)', segment)
result = []
for elem, num_str in matches:
qty = int(num_str) if num_str else 1
result.append((elem, qty))
return tuple(result)
def parse_nested(formula):
"""
递归解析含括号的化学式,返回嵌套元组。
示例: 'Al2(SO4)3' → (('Al', 2), ((('S', 1), ('O', 4)), 3))
"""
# 移除空格(增强鲁棒性)
formula = formula.replace(' ', '')
if not formula:
return tuple()
result = []
i = 0
while i 0:
if formula[j] == '(':
depth += 1
elif formula[j] == ')':
depth -= 1
j += 1
if depth != 0:
raise ValueError(f"Unmatched parentheses in '{formula}'")
# 提取括号内内容及后续数字
inner = formula[i+1:j-1]
# 查找右括号后的数字(可能为空)
num_match = re.match(r'(\d*)', formula[j:])
num_str = num_match.group(1) if num_match else ''
qty = int(num_str) if num_str else 1
# 递归解析内部,并打包为 (inner_parsed, quantity)
result.append((parse_nested(inner), qty))
i = j + len(num_str)
else:
# 匹配下一个元素段(直到遇到 ( 或结尾)
elem_match = re.match(r'([A-Z][a-z]*\d*)', formula[i:])
if not elem_match:
raise ValueError(f"Invalid token at position {i}: '{formula[i:]}'")
token = elem_match.group(1)
result.append(parse_formula(token))
i += len(token)
return tuple(result)
# ✅ 使用示例
if __name__ == "__main__":
test_cases = ["O2", "SO4", "Al2(SO4)3", "Ca(OH)2", "K3[Fe(CN)6]"] # 注意:此版暂不支持方括号,可按需扩展
for f in test_cases[:3]: # 前三个典型示例
try:
parsed = parse_nested(f)
print(f"{f} → {parsed}")
except Exception as e:
print(f"{f} → Error: {e}")
⚠️ 注意事项与扩展建议
- 括号类型:当前版本仅处理圆括号 ();若需支持 [] 或 {}(如配位化合物),需在 parse_nested 中扩展括号匹配逻辑;
- 错误处理:实际应用中应增加更完善的语法校验(如非法字符、孤立括号、元素符号不存在等);
- 性能优化:对超长公式,可改用迭代栈模拟递归,避免 Python 默认递归深度限制;
- 下一步配平:获得嵌套结构后,可通过深度优先遍历+字典累加,将整个式子扁平化为 {'Al': 2, 'S': 3, 'O': 12},进而构建线性方程组求解系数。
该方案完全基于标准库,逻辑清晰、易于调试和定制,是手动实现化学式解析的理想起点。











