鱼C论坛

 找回密码
 立即注册
查看: 6744|回复: 20

[技术交流] Python: 每日一题 61

[复制链接]
发表于 2017-6-7 19:50:21 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 ooxx7788 于 2017-6-8 15:54 编辑

化学是我大学的主要基础专业课,刚好看见了个跟化学有一点点关系,翻译又不需要太长的题目,赶快搬过来。

你会给到一个字符串形式的分子式,请你数出其中的各元素的原子数。具体要求看例子:

  1. water = 'H2O'
  2. parse_molecule(water)                 # return {H: 2, O: 1}

  3. magnesium_hydroxide = 'Mg(OH)2'
  4. parse_molecule(magnesium_hydroxide)   # return {Mg: 1, O: 2, H: 2}

  5. fremy_salt = 'K4[ON(SO3)2]2'
  6. parse_molecule(fremySalt)             # return {K: 4, O: 14, N: 2, S: 4}
复制代码


我想原子数怎么数应该不用我多解释吧,注意计算顺序哦,一不小心就算错了。还有怎么区分元素呢?哈哈,慢慢想吧!我看看有没有人会把元素周期表给抄上来。


游客,如果您要查看本帖隐藏内容请回复

本帖被以下淘专辑推荐:

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2017-6-7 21:40:46 | 显示全部楼层

                               
登录/注册后可看大图
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-6-7 21:41:22 | 显示全部楼层
我叫雷锋,不用谢
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-6-7 21:47:47 | 显示全部楼层

这是你的百度!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-6-7 23:48:07 | 显示全部楼层
本帖最后由 SixPy 于 2017-6-7 23:50 编辑
  1. import re
  2. from collections import Counter

  3. def parse_molecule(exp):
  4.         ptns=[re.compile(r'\[([^\[\]]+)\](\d+)'),
  5.               re.compile(r'\(([^()]+)\)(\d+)'),
  6.               re.compile(r'([A-Z][a-z]?)(\d+)')]
  7.         repl=lambda m: m.group(1) * int(m.group(2))
  8.         for ptn in ptns:
  9.                 while ptn.search(exp):
  10.                         exp=ptn.sub(repl,exp)
  11.         exp=re.sub(r'([A-Z][a-z]?)',r'\1 ',exp).split()
  12.         return dict(Counter(exp))

  13. exp=('H2O','Mg(OH)2','K4[ON(SO3)2]2')
  14. for e in exp:
  15.         print('%-15s%s'%(e,parse_molecule(e)))

复制代码

  1. H2O            {'O': 1, 'H': 2}
  2. Mg(OH)2        {'O': 2, 'H': 2, 'Mg': 1}
  3. K4[ON(SO3)2]2  {'O': 14, 'N': 2, 'K': 4, 'S': 4}
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2017-6-8 16:08:59 | 显示全部楼层


大神给的答案基本正确,只是在以下几个化学式有点问题。第一个化学式有点特殊,光有括号。后面两个大括弧的化学式我也没见过。
  1. Should parse cyclopentadienyliron dicarbonyl dimer: (C5H5)Fe(CO)2CH3
  2. Should parse really weird molecule: As2{Be4C5[BCo3(CO2)3]2}4Cu5
  3. Should parse hexol sulphate: {[Co(NH3)4(OH)2]3Co}(SO4)3
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-6-8 17:02:29 | 显示全部楼层
ooxx7788 发表于 2017-6-8 16:08
大神给的答案基本正确,只是在以下几个化学式有点问题。第一个化学式有点特殊,光有括号。后面两个大括 ...
  1. import re
  2. from collections import Counter

  3. def parse_molecule(exp):
  4.         ptns=[re.compile(r'\{([^{}]+)\}(\d+)'),
  5.               re.compile(r'\[([^\[\]]+)\](\d+)'),
  6.               re.compile(r'\(([^()]+)\)(\d+)'),
  7.               re.compile(r'([A-Z][a-z]?)(\d+)')]
  8.         repl=lambda m: m.group(1) * int(m.group(2))
  9.         for ptn in ptns:
  10.                 while ptn.search(exp):
  11.                         exp=ptn.sub(repl,exp)
  12.         exp=re.sub(r'[{}\[\]()]','',exp)
  13.         exp=re.sub(r'([A-Z][a-z]?)',r'\1 ',exp).split()
  14.         return dict(Counter(exp))

  15. exp=('H2O','Mg(OH)2','K4[ON(SO3)2]2','(C5H5)Fe(CO)2CH3',
  16.      'As2{Be4C5[BCo3(CO2)3]2}4Cu5','{[Co(NH3)4(OH)2]3Co}(SO4)3')
  17. for e in exp:
  18.         print('%s\n%s\n'%(e,parse_molecule(e)))
复制代码

  1. H2O
  2. {'H': 2, 'O': 1}

  3. Mg(OH)2
  4. {'H': 2, 'Mg': 1, 'O': 2}

  5. K4[ON(SO3)2]2
  6. {'S': 4, 'O': 14, 'K': 4, 'N': 2}

  7. (C5H5)Fe(CO)2CH3
  8. {'H': 8, 'C': 8, 'Fe': 1, 'O': 2}

  9. As2{Be4C5[BCo3(CO2)3]2}4Cu5
  10. {'As': 2, 'C': 44, 'Co': 24, 'Be': 16, 'B': 8, 'Cu': 5, 'O': 48}

  11. {[Co(NH3)4(OH)2]3Co}(SO4)3
  12. {'H': 42, 'Co': 4, 'N': 12, 'S': 3, 'O': 18}
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-6-8 17:30:35 | 显示全部楼层
学习
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2017-6-9 07:59:36 | 显示全部楼层
看看
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2017-6-13 16:38:38 | 显示全部楼层
反正写了一个函数,你上面这几个是没问题,不知道能不能通用
  1. import re

  2. def parse_molecule(f):
  3.   lis = re.findall("[A-Z][a-z]*",f)
  4.   nums = re.findall("\d+",f)
  5.   for i in set(lis):
  6.     f = f.replace(i,"'"+i+"'")
  7.   if "(" in f:
  8.     for j in set(nums):
  9.       f = f.replace(j,"*"+str(j))
  10.   else:
  11.     for j in set(nums):
  12.       f = f.replace(j,"*"+str(j)+"+")
  13.   f = f.replace("**","*").replace("(","+(").replace("[","+(").replace("]",")").replace("''","'+'")
  14.   k = eval(f)
  15.   dic = {i:k.count(i) for i in set(lis)}
  16.   print(dic)
  17.   return dic
复制代码


输出
  1. water = 'H2O'
  2. magnesium_hydroxide = 'Mg(OH)2'
  3. fremy_salt = 'K4[ON(SO3)2]2'
  4. parse_molecule(water)
  5. parse_molecule(magnesium_hydroxide)
  6. parse_molecule(fremy_salt)

  7. {'H': 2, 'O': 1}
  8. {'O': 2, 'H': 2, 'Mg': 1}
  9. {'O': 14, 'N': 2, 'S': 4, 'K': 4}
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-6-16 17:46:41 | 显示全部楼层
gopythoner 发表于 2017-6-13 16:38
反正写了一个函数,你上面这几个是没问题,不知道能不能通用

自答,你后面发的那几个复杂的化学式我这个函数解不出来
看来还是不通用啊
这题有点难
其实我老是想着怎么能用eval()方法来解,但是不知道怎么构造出来可以用这个方法的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-7-24 18:55:16 | 显示全部楼层
本帖最后由 solomonxian 于 2017-7-24 18:56 编辑

不知道很长的分子式是什么样子的,有没有另外的符号,假设就是例子中的那样输入吧

分四步:
1、处理元素:大写字母单独一个,小写字母跟前一个大写字母搭配
2、递归拆除括号:括号内数据乘以括号后数字,扩展
3、处理数字:用数字与前字符串乘机扩展列表
4、返回统计信息
  1. def parse_molecule(s):
  2.     """parse_molecule(str) -> dict, counts the atoms of each element"""
  3.     list_s = list(s)
  4.     for i in range(len(s)): # 处理元素
  5.         if s[i].islower():
  6.             list_s[i] = list_s[i-1]+s[i]
  7.             list_s[i-1] = ""
  8.     #print(list_s)
  9.     def flatten_lst(lst,m=0): # 拆除括号
  10.         for j in range(len(lst)):
  11.             if lst[j] in {'[','(','{'}:
  12.                 if m==0: start = j # 记录左括号初始位置
  13.                 m +=1
  14.             elif lst[j] in {']',')','}'}:
  15.                 m -=1
  16.             else:
  17.                 continue

  18.             if m==0: # 等于0表明括号配对完成
  19.                 if lst[j+1].isdigit():
  20.                     new = lst[start+1:j]*(int(lst[j+1])-1) # 括号内容数乘后面数字
  21.                     lst.pop(j+1)  # 从后往前删除数字、右括号、左括号
  22.                 else:
  23.                     new = [] # 括号右不是数字时为空
  24.                 lst.pop(j)
  25.                 lst.pop(start)
  26.                 lst.extend(new) # 更新列表
  27.                 return flatten_lst(lst) # 递归拆括号,直到成功完成for循环
  28.         else:
  29.            # print(lst)
  30.             for k in range(len(lst)): # 处理数字
  31.                 if lst[k].isdigit():
  32.                     lst.extend(lst[k-1:k]*(int(lst[k])-1))
  33.             return {i:lst.count(i) for i in set(lst) if i.isalpha()}
  34.     return flatten_lst(list_s)
复制代码

试下用re模块做,感觉跟作弊一样方便

  1. import re

  2. def parse_molecule2(s):
  3.     p = re.compile(r"""[\[\(\{]    # 以左括号开头
  4.                   [^\[\]\(\)\{\}]+   # 中间不包含任何括号
  5.                   [\]\)\}]\d*""",re.VERBOSE)  # 以右括号加可能数字结尾
  6.     while 1:
  7.         try:
  8.             sub_s = p.search(s).group()
  9.             
  10.             numbers = ['0']
  11.             for j in sub_s[::-1]: # 这段用来找括号外的数字(2~∞),没有就当是1
  12.                 if j.isdigit():
  13.                     numbers.append(j)
  14.                 else:
  15.                     break
  16.             number = int("".join(numbers)) if len(numbers)>1 else 1
  17.             s = p.sub(sub_s[1:-len(numbers)]*number,s,1)
  18.         except AttributeError:
  19.             break  # 找不到括号就退出
  20.         
  21.     lst = list(s)
  22.     for i in range(len(s)):
  23.         if s[i].islower():
  24.             lst[i-1], lst[i] = "",lst[i-1]+lst[i]
  25.         if s[i].isdigit():
  26.             lst.extend(lst[i-1:i]*(int(lst[i])-1))
  27.     return {i:lst.count(i) for i in set(lst) if i.isalpha()}
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-9-4 17:28:37 | 显示全部楼层
1
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2019-1-14 14:59:11 | 显示全部楼层
看看
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2019-1-14 15:01:11 | 显示全部楼层
本帖最后由 咕咕鸡鸽鸽 于 2019-1-14 15:03 编辑

同不会正则
  1. def fun61(str1):
  2.     #先找出[]()这些括号,分离,先只考虑只有一个括号
  3.     index1 = 0
  4.     index2 = 0
  5.     index3 = 0
  6.     index4 = 0
  7.     dict1 = {}
  8.     if not str1[-1].isdigit():
  9.         str1 += "1"
  10.     for each in str1:
  11.         if not each.isalnum():
  12.             if each == "[":
  13.                 index1 = str1.index(each)
  14.             elif each == "]":
  15.                 index2 = str1.index(each)
  16.             elif each == "(":
  17.                 index3 = str1.index(each)               
  18.             elif each == ")":
  19.                 index4 = str1.index(each)

  20.     for each in range(len(str1)):
  21.         #判断,如Mg类的元素
  22.         if str1[each].isupper() and str1[each+1].islower():
  23.             element = str1[each:each+2]
  24.             if str1[each+2].isdigit():               
  25.                 multiple = int(str1[each+2])               
  26.             else:
  27.                 multiple = 1
  28.         elif str1[each].isupper() and not str1[each+1].islower():
  29.             element = str1[each]
  30.             if str1[each+1].isdigit():
  31.                 multiple = int(str1[each+1])
  32.             else:
  33.                 multiple = 1

  34.         #用引索值 得出元素是否在所分离的列表里面
  35.         if element:
  36.             if index1 < each < index2:
  37.                 multiple *= int(str1[index2+1])
  38.             if index3 < each < index4:
  39.                 multiple *= int(str1[index4+1])

  40.             if element not in dict1:
  41.                 dict1[element] = multiple
  42.             else:
  43.                 dict1[element] += multiple
  44.             element = ""
  45.             
  46.     return dict1
  47.    

  48. #fun61("H2O")
  49. #fun61("Mg(OH)2")
  50. print(fun61("K4[ON(SO3)2]2"))
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-9-15 11:50:13 | 显示全部楼层

枯了 不会正则表达式
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-6-15 13:20:25 | 显示全部楼层
from collections import Counter

def parse_molecule(string):
    c = Counter(string)
    return c
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-6-15 22:42:08 From FishC Mobile | 显示全部楼层
可以简单说说思路吗?没看明白,多谢。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-7-16 21:42:21 | 显示全部楼层
1
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-7-30 14:42:33 | 显示全部楼层
学习一下
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-7-10 12:50

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表