Python: 每日一题 61
本帖最后由 ooxx7788 于 2017-6-8 15:54 编辑化学是我大学的主要基础专业课,刚好看见了个跟化学有一点点关系,翻译又不需要太长的题目,赶快搬过来。
你会给到一个字符串形式的分子式,请你数出其中的各元素的原子数。具体要求看例子:
water = 'H2O'
parse_molecule(water) # return {H: 2, O: 1}
magnesium_hydroxide = 'Mg(OH)2'
parse_molecule(magnesium_hydroxide) # return {Mg: 1, O: 2, H: 2}
fremy_salt = 'K42'
parse_molecule(fremySalt) # return {K: 4, O: 14, N: 2, S: 4}
我想原子数怎么数应该不用我多解释吧,注意计算顺序哦,一不小心就算错了。还有怎么区分元素呢?哈哈,慢慢想吧!我看看有没有人会把元素周期表给抄上来。
**** Hidden Message ***** http://g.hiphotos.baidu.com/zhidao/pic/item/5d6034a85edf8db1ed5b3ea10823dd54574e74f9.jpg 我叫雷锋,不用谢{:10_254:}{:10_256:} Messj 发表于 2017-6-7 21:40
这是你的百度! 本帖最后由 SixPy 于 2017-6-7 23:50 编辑
import re
from collections import Counter
def parse_molecule(exp):
ptns=]+)\](\d+)'),
re.compile(r'\(([^()]+)\)(\d+)'),
re.compile(r'(?)(\d+)')]
repl=lambda m: m.group(1) * int(m.group(2))
for ptn in ptns:
while ptn.search(exp):
exp=ptn.sub(repl,exp)
exp=re.sub(r'(?)',r'\1 ',exp).split()
return dict(Counter(exp))
exp=('H2O','Mg(OH)2','K42')
for e in exp:
print('%-15s%s'%(e,parse_molecule(e)))
H2O {'O': 1, 'H': 2}
Mg(OH)2 {'O': 2, 'H': 2, 'Mg': 1}
K42{'O': 14, 'N': 2, 'K': 4, 'S': 4} SixPy 发表于 2017-6-7 23:48
大神给的答案基本正确,只是在以下几个化学式有点问题。第一个化学式有点特殊,光有括号。后面两个大括弧的化学式我也没见过。
Should parse cyclopentadienyliron dicarbonyl dimer: (C5H5)Fe(CO)2CH3
Should parse really weird molecule: As2{Be4C52}4Cu5
Should parse hexol sulphate: {3Co}(SO4)3
ooxx7788 发表于 2017-6-8 16:08
大神给的答案基本正确,只是在以下几个化学式有点问题。第一个化学式有点特殊,光有括号。后面两个大括 ...
import re
from collections import Counter
def parse_molecule(exp):
ptns=+)\}(\d+)'),
re.compile(r'\[([^\[\]]+)\](\d+)'),
re.compile(r'\(([^()]+)\)(\d+)'),
re.compile(r'(?)(\d+)')]
repl=lambda m: m.group(1) * int(m.group(2))
for ptn in ptns:
while ptn.search(exp):
exp=ptn.sub(repl,exp)
exp=re.sub(r'[{}\[\]()]','',exp)
exp=re.sub(r'(?)',r'\1 ',exp).split()
return dict(Counter(exp))
exp=('H2O','Mg(OH)2','K42','(C5H5)Fe(CO)2CH3',
'As2{Be4C52}4Cu5','{3Co}(SO4)3')
for e in exp:
print('%s\n%s\n'%(e,parse_molecule(e)))
H2O
{'H': 2, 'O': 1}
Mg(OH)2
{'H': 2, 'Mg': 1, 'O': 2}
K42
{'S': 4, 'O': 14, 'K': 4, 'N': 2}
(C5H5)Fe(CO)2CH3
{'H': 8, 'C': 8, 'Fe': 1, 'O': 2}
As2{Be4C52}4Cu5
{'As': 2, 'C': 44, 'Co': 24, 'Be': 16, 'B': 8, 'Cu': 5, 'O': 48}
{3Co}(SO4)3
{'H': 42, 'Co': 4, 'N': 12, 'S': 3, 'O': 18} 学习 看看
反正写了一个函数,你上面这几个是没问题,不知道能不能通用
import re
def parse_molecule(f):
lis = re.findall("*",f)
nums = re.findall("\d+",f)
for i in set(lis):
f = f.replace(i,"'"+i+"'")
if "(" in f:
for j in set(nums):
f = f.replace(j,"*"+str(j))
else:
for j in set(nums):
f = f.replace(j,"*"+str(j)+"+")
f = f.replace("**","*").replace("(","+(").replace("[","+(").replace("]",")").replace("''","'+'")
k = eval(f)
dic = {i:k.count(i) for i in set(lis)}
print(dic)
return dic
输出
water = 'H2O'
magnesium_hydroxide = 'Mg(OH)2'
fremy_salt = 'K42'
parse_molecule(water)
parse_molecule(magnesium_hydroxide)
parse_molecule(fremy_salt)
{'H': 2, 'O': 1}
{'O': 2, 'H': 2, 'Mg': 1}
{'O': 14, 'N': 2, 'S': 4, 'K': 4} gopythoner 发表于 2017-6-13 16:38
反正写了一个函数,你上面这几个是没问题,不知道能不能通用
自答,你后面发的那几个复杂的化学式我这个函数解不出来
看来还是不通用啊
这题有点难
其实我老是想着怎么能用eval()方法来解,但是不知道怎么构造出来可以用这个方法的 本帖最后由 solomonxian 于 2017-7-24 18:56 编辑
不知道很长的分子式是什么样子的,有没有另外的符号,假设就是例子中的那样输入吧
分四步:
1、处理元素:大写字母单独一个,小写字母跟前一个大写字母搭配
2、递归拆除括号:括号内数据乘以括号后数字,扩展
3、处理数字:用数字与前字符串乘机扩展列表
4、返回统计信息
def parse_molecule(s):
"""parse_molecule(str) -> dict, counts the atoms of each element"""
list_s = list(s)
for i in range(len(s)): # 处理元素
if s.islower():
list_s = list_s+s
list_s = ""
#print(list_s)
def flatten_lst(lst,m=0): # 拆除括号
for j in range(len(lst)):
if lst in {'[','(','{'}:
if m==0: start = j # 记录左括号初始位置
m +=1
elif lst in {']',')','}'}:
m -=1
else:
continue
if m==0: # 等于0表明括号配对完成
if lst.isdigit():
new = lst*(int(lst)-1) # 括号内容数乘后面数字
lst.pop(j+1)# 从后往前删除数字、右括号、左括号
else:
new = [] # 括号右不是数字时为空
lst.pop(j)
lst.pop(start)
lst.extend(new) # 更新列表
return flatten_lst(lst) # 递归拆括号,直到成功完成for循环
else:
# print(lst)
for k in range(len(lst)): # 处理数字
if lst.isdigit():
lst.extend(lst*(int(lst)-1))
return {i:lst.count(i) for i in set(lst) if i.isalpha()}
return flatten_lst(list_s)
试下用re模块做,感觉跟作弊一样方便
import re
def parse_molecule2(s):
p = re.compile(r"""[\[\(\{] # 以左括号开头
[^\[\]\(\)\{\}]+ # 中间不包含任何括号
[\]\)\}]\d*""",re.VERBOSE)# 以右括号加可能数字结尾
while 1:
try:
sub_s = p.search(s).group()
numbers = ['0']
for j in sub_s[::-1]: # 这段用来找括号外的数字(2~∞),没有就当是1
if j.isdigit():
numbers.append(j)
else:
break
number = int("".join(numbers)) if len(numbers)>1 else 1
s = p.sub(sub_s*number,s,1)
except AttributeError:
break# 找不到括号就退出
lst = list(s)
for i in range(len(s)):
if s.islower():
lst, lst = "",lst+lst
if s.isdigit():
lst.extend(lst*(int(lst)-1))
return {i:lst.count(i) for i in set(lst) if i.isalpha()} 1 看看 本帖最后由 咕咕鸡鸽鸽 于 2019-1-14 15:03 编辑
同不会正则{:10_285:}
def fun61(str1):
#先找出[]()这些括号,分离,先只考虑只有一个括号
index1 = 0
index2 = 0
index3 = 0
index4 = 0
dict1 = {}
if not str1[-1].isdigit():
str1 += "1"
for each in str1:
if not each.isalnum():
if each == "[":
index1 = str1.index(each)
elif each == "]":
index2 = str1.index(each)
elif each == "(":
index3 = str1.index(each)
elif each == ")":
index4 = str1.index(each)
for each in range(len(str1)):
#判断,如Mg类的元素
if str1.isupper() and str1.islower():
element = str1
if str1.isdigit():
multiple = int(str1)
else:
multiple = 1
elif str1.isupper() and not str1.islower():
element = str1
if str1.isdigit():
multiple = int(str1)
else:
multiple = 1
#用引索值 得出元素是否在所分离的列表里面
if element:
if index1 < each < index2:
multiple *= int(str1)
if index3 < each < index4:
multiple *= int(str1)
if element not in dict1:
dict1 = multiple
else:
dict1 += multiple
element = ""
return dict1
#fun61("H2O")
#fun61("Mg(OH)2")
print(fun61("K42")) 咕咕鸡鸽鸽 发表于 2019-1-14 15:01
同不会正则
枯了 不会正则表达式 from collections import Counter
def parse_molecule(string):
c = Counter(string)
return c 可以简单说说思路吗?没看明白,多谢。 1 学习一下
页:
[1]
2