我正在尝试为一个应用程序编写一个方法,该应用程序采用像“CH3COOH”这样的化学公式并返回某种充满符号的集合。
CH3COOH 将返回 [C,H,H,H,C,O,O,H]
我已经有了一些可以工作的东西,但是它非常复杂,并且使用了大量的代码以及许多嵌套的 if-else 结构和循环。
有没有办法通过使用某种带有 String.split 的正则表达式或其他一些出色的简单代码来做到这一点?
我编写了几篇关于如何解析分子式的系列文章,包括更复杂的公式,如 C6H2(NO2)3CH3 。
最近的是我在 PyCon2010 上的演讲“ PLY 和 PyParsing ”,我使用分子式评估器作为我的示例问题比较了这两个 Python 解析系统。甚至还有我的演示视频。
该演示文稿基于我使用 ANTLR 开发分子式解析器的三部分系列文章。在第 3 部分中,我将 ANTLR 解决方案与手写的正则表达式解析器以及 PLY 和 PyParsing 中的解决方案进行了比较。
regexp 和 PLY 解决方案最初是在一个由两部分组成的系列中开发的,该系列介绍了用 Python 编写解析器的两种方式。
正则表达式解决方案和基础 ANTLR/PLY/PyParsing 解决方案使用像 [AZ][az]?\d* 这样的正则表达式来匹配公式中的项。这就是@David M 的建议。
这是用Python解决的
import re
# element_name is: capital letter followed by optional lower-case
# count is: empty string (so the count is 1), or a set of digits
element_pat = re.compile("([A-Z][a-z]?)(\d*)")
all_elements = []
for (element_name, count) in element_pat.findall("CH3COOH"):
if count == "":
count = 1
else:
count = int(count)
all_elements.extend([element_name] * count)
print all_elements
当我运行这个(硬编码使用乙酸,CH3COOH)时,我得到
['C', 'H', 'H', 'H', 'C', 'O', 'O', 'H']
请注意,这段代码假定分子式是正确的。如果你给它“##$%^O2#$$#”之类的东西,那么它将忽略它不知道的字段并给出['O','O']。如果你不想要那个,那么你必须让它更健壮一点。
如果您想支持更复杂的公式,例如 C6H2(NO2)3CH3,那么您需要了解一些树数据结构,特别是(正如@Roman 指出的)抽象语法树(通常称为 AST)。这太复杂了,无法进入这里,因此请参阅我的演讲和论文了解更多详细信息。
假设它的大小写正确,等式中的每个符号都匹配这个正则表达式:
[A-Z][a-z]*\d*
(对于受化学挑战的元素,元素的符号总是大写字母,后跟可选的小写字母 1 或可能的 2 - 例如 Hg 表示汞)
您可以像这样捕获元素符号和组中的数字:
([A-Z][a-z]*)(\d*)
所以是的,理论上这将是正则表达式可以提供帮助的东西。如果你正在处理像 C 6 H 2 (NO 2 ) 3 (CH 3 ) 3这样的公式,那么你的工作当然会有点困难......
您是否考虑过用化学标记语言表达您的化学式?它非常通用,并且有很多工具/查看器可以将这些化学公式或化合物呈现为 2D 到 3D。
我正在开发一个需要对化学公式进行摩尔质量计算的程序,因此我创建了一个适用于各种公式的解决方案。
例如,“(CH3)16(Tc(H2O)3CO(BrFe3(ReCl)3(SO4)2)2)2MnO4”将导致“16C 48H 2Tc 12H 6O 2C 2O 4Br 12Fe 12Re 12Cl 8S 32O Mn 4O”(这种化合物是合成的,但是,嘿,它有效!)
这段代码是用 C# 编写的,所以我没有发布它。如果你有兴趣我可以发给你。在注意到 java 标签之前,我实际上写了一个完整的答案。
无论如何,它的工作原理基本上是递归地对括号匹配的原子块进行分组。它不处理诸如 2Pb 之类的系数(但 (Pb)2 或 Pb2 确实有效)或带电化合物(例如 OH-)。
绝不是简单或优雅的。我确实想要一个可行的解决方案,所以我知道有更好的方法(我什至从未尝试过正则表达式!)。但它适用于我需要的公式,也许它也适合你的。
这是我运行它的一些测试用例。看看它们,让我知道 C# 代码是否仍然对您有用。格式为(输入,预期输出)
("Pb ", " Pb");
("H ", " H");
("Pb2 ", " 2Pb");
("H2 ", " 2H");
("3Pb2 ", " 6Pb");
("Pb2SO4", " 2Pb S 4O");
("PbH2 ", " Pb 2H");
("(PbH2)2 ", " 2Pb 4H");
("(CCC)2 ", " 2C 2C 2C");
("Pb(H2)2 ", " Pb 4H");
("(Pb(H2)2)2 ", " 2Pb 8H");
("(Pb(H2)2)2NO3 ", " 2Pb 8H N 3O");
("(Ag(Pb(H2)2)2)2SO4 ", " 2Ag 4Pb 16H S 4O");
("Pb(CH3(CH2)2CH3)2", " Pb 2C 6H 4C 8H 2C 6H");
("Na2(CH3(CH2)2CH3)2", " 2Na 2C 6H 4C 8H 2C 6H");
("Tc(H2O)3Fe3(SO4)2", " Tc 6H 3O 3Fe 2S 8O");
("Tc(H2O)3(Fe3(SO4)2)2", " Tc 6H 3O 6Fe 4S 16O");
("(Tc(H2O)3(Fe3(SO4)2)2)2", " 2Tc 12H 6O 12Fe 8S 32O");
("(Tc(H2O)3CO(Fe3(SO4)2)2)2", " 2Tc 12H 6O 2C 2O 12Fe 8S 32O");
("(Tc(H2O)3CO(BrFe3(ReCl)3(SO4)2)2)2MnO4", " 2Tc 12H 6O 2C 2O 4Br 12Fe 12Re 12Cl 8S 32O Mn 4O");
("(CH3)16(Tc(H2O)3CO(BrFe3(ReCl)3(SO4)2)2)2MnO4", " 16C 48H 2Tc 12H 6O 2C 2O 4Br 12Fe 12Re 12Cl 8S 32O Mn 4O");