所以我试着编写一些代码来告诉我任何给定化合物中元素的数量。我甚至不知道从哪里开始:我试着编写一些东西,但后来意识到它只适用于简单的化合物(或者根本不起作用)。下面是我想要的一个例子:
>>> function_input : 'NaMg3Al6(BO3)3Si6O18(OH)4', 'O'
>>> function_return : 31到目前为止,我的代码非常混乱(IT不工作,它只是说明了我粗略的思考过程):
def get_pos_from_count(string: str, letter: str):
count = string.count(letter)
lens = [-1]
for i in range(count):
lens += [string[lens[i] + 1:].index(letter) + lens[i] + 1]
return lens[1:]
def find_number(string, letter):
if string.count(letter) == 0: return 0
numbers = '1234567890'
try:
mul1 = int(string[0])
except ValueError:
mul1 = 0
mul2 = []
sub_ = 1
list_of_positions = get_pos_from_count(string, letter)
for i in list_of_positions:
try:
sub_ += int(string[i + 1]) if string[i + 1] in numbers else 0
except IndexError: pass
if string[i + 1:].count(')') > string[i + 1].count('('):
try:
mul2 += int(string[string[i + 1:].count(')') + 1])
except (IndexError, ValueError): pass
return mul1 * sub_ * mul2我试图实施的办法是:
string)
)。
但后来我意识到我的代码要么非常长,要么需要递归,我不知道如何在这里应用。
如果可能的话,我想要一个半工作的函数,但是关于如何处理这个问题的快速提示也是有帮助的!
如果可能的话,我不想使用外部库。
tl;dr:元素原子性的This question,没有外部库(如果可能的话)。
编辑:是的,我链接的问题确实有关于如何做到这一点的提示,但是当我试图使任何代码只对一个元素工作,并将其权重设置为1时,我遇到了许多我不知道要解决的问题。
发布于 2022-01-31 19:59:07
让我们把这项任务分成三个部分:
将字符串标记为元素、数字的列表,并将方括号标记为具有嵌套列表的嵌套列表。brackets;
。
介绍我的工具:
collections.counter.from more_itertools import split_when, pairwise
from itertools import chain
from collections import Counter
def nest_brackets(tokens, i = 0):
l = []
while i < len(tokens):
if tokens[i] == ')':
return i,l
elif tokens[i] == '(':
i,subl = nest_brackets(tokens, i+1)
l.append(subl)
else:
l.append(tokens[i])
i += 1
return i,l
def parse_compound(s):
tokens = [''.join(t) for t in split_when(s, lambda a,b: b.isupper() or b in '()' or (b.isdigit() and not a.isdigit()))]
tokens = [(int(t) if t.isdigit() else t) for t in tokens]
i, l = nest_brackets(tokens)
assert(i == len(tokens)) # crash if unmatched ')'
return l
def count_elems(parsed_compound):
c = Counter()
for a,b in pairwise(chain(parsed_compound, (1,))):
if not isinstance(a, int):
subcounter = count_elems(a) if isinstance(a, list) else {a: 1}
n = b if isinstance(b, int) else 1
for elem,k in subcounter.items():
c[elem] += k * n
return c
s = 'NaMg3Al6(B(CO2)3)3Si6O18(OH)4'
l = parse_compound(s)
print(l)
# ['Na', 'Mg', 3, 'Al', 6, ['B', ['C', 'O', 2], 3], 3, 'Si', 6, 'O', 18, ['O', 'H'], 4]
c = count_elems(l)
print(c)
# Counter({'O': 40, 'C': 9, 'Al': 6, 'Si': 6, 'Mg': 3, 'B': 3, 'Na': 1})
print(c['O'])
# 40发布于 2022-01-31 12:50:34
尝试使用这个递归函数:
import re
def find_number(s, e):
if s == '':
return 0
x = re.search('\(([A-Za-z0-9]*)\)([0-9]*)', s)
if x is not None:
return (find_number(s[:x.start()] + s[x.end():], e) +
find_number(x.groups()[0], e) * int(x.groups()[1] or '1'))
return sum(int(x.groups()[0] or '1')
for x in re.finditer(f'{e}([0-9]*)', s))示例:
>>> find_number('NaMg3Al6(BO3)3Si6O18(OH)4', 'O')
31https://stackoverflow.com/questions/70924875
复制相似问题