假设我们有一个化学式,表示为字符串。这个化学式可能包含嵌套的元素和非整数化学计量数。我们的目标是使用 pyparsing 库来解析这个化学式,并提取出化学式中出现的每个元素及其对应的总化学计量数。
2、解决方案
为了解决这个问题,我们可以使用 pyparsing 库来定义一个解析化学式的语法。这个语法需要能够识别出元素、化学计量数、括号和逗号等符号。此外,我们还需要使用递归来处理嵌套的元素。
以下是使用 pyparsing 库定义的语法:
from pyparsing import Word, Group, ZeroOrMore, Combine,\
Optional, OneOrMore, ParseException, Literal, nums,\
Suppress, Dict, Forward
caps = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
lowers = caps.lower()
digits = "0123456789"
integer = Word( digits )
parl = Literal("(").suppress()
parr = Literal(")").suppress()
element = Word( caps, lowers )
separator = Literal( "," ).setParseAction(lambda s,l,t: t[0].replace(',','.')) | Literal( "." )
nreal = (Combine( integer + Optional( separator +\
Optional( integer ) ))\
| Combine( separator + integer )).setParseAction( lambda s,l,t: [ float(t[0]) ] )
block = Forward()
groupElem = Group( element + Optional( nreal, default=1)) ^ \
Group( parl + block + parr + Optional( nreal,default=1 ) )
block << groupElem + ZeroOrMore( groupElem )
formula = OneOrMore( block )
上述语法使用了 pyparsing 库中的各种解析元素,包括单词、组、零个或多个、组合、可选、一个或多个、解析异常、文字、数字、抑制、字典和前向声明等。这些解析元素可以帮助我们识别出化学式中的各种符号。
接下来,我们需要定义一个解析动作,用于处理化学式中出现的化学计量数。这个解析动作将把化学计量数转换为浮点数。
nreal.setParseAction( lambda s,l,t: [ float(t[0]) ] )
最后,我们需要定义一个递归函数,用于处理嵌套的元素。这个递归函数将把化学式中的嵌套元素展开,并将其添加到结果列表中。
def solu(formula):
final = []
def diver(entr,mult=1):
resul = list()
# If modi is empty, it is an enclosed group
# And we must multiply everything inside by modi
if entr.modi != '':
for y in entr:
try:
resul.append(diver(y,entr.modi))
except AttributeError:
pass
# Else, it is just an atom, and we return it
else:
resul.append(entr.elem)
resul.append(entr.esteq*mult)
return resul
def doubles(entr):
resul = []
# If entr does not contain lists
# It is an atom
if sum([1 for y in entr if isinstance(y,list)]) == 0:
final.append(entr)
return entr
else:
# And if it isn't an atom? We dive further
# and call doubles until it is an atom
for y in entr:
doubles(y)
for member in formula:
# If member is already an atom, add it directly to final
if sum([1 for x in diver(member) if isinstance(x,list)]) == 0:
final.append(diver(member))
else:
# If not, call doubles on the clean member (without modi)
# and it takes care of adding atoms to final
doubles(diver(member))
return final
上述递归函数使用了 pyparsing 库中的各种解析元素,包括组、零个或多个、组合、可选、一个或多个、解析异常、文字、数字、抑制、字典和前向声明等。这些解析元素可以帮助我们识别出化学式中的各种符号。
通过使用上述语法和解析动作,我们可以将化学式中的外层符号改变内层符号。
以下是一些测试用例:
>>> solu(formula.parseString('C6H8(OH)4'))
[['C', 6.0], ['H', 8.0], ['O', 4.0], ['H', 4.0]]
>>> solu(formula.parseString('(H2O)2OH'))
[['H', 5.0], ['O', 3.0]]
这些测试用例表明,我们的解决方案可以正确地将化学式中的外层符号改变内层符号。