日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

史上最最最没用程序——自写平衡化学方程式

發布時間:2023/12/20 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 史上最最最没用程序——自写平衡化学方程式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

創作歷史

  • 前言
  • 例子
  • 運行截圖
    • bce-console.exe運行結果(pip install bce安裝)
    • 總程序運行結果
  • 需要的庫
  • 步驟
    • 拆分等式左右側
    • 拆分每個化學物質和+-號
      • 化學物質組成
      • 化學物質提取
    • 統計每個化學物質內每個化學元素的數量
      • 判斷等式雙方元素種類是否一致
      • 計算左右雙方元素數量,獲取每個元素在每個物質中的占比
    • 解化學元素守恒方程
      • 按物質名稱創建符號變量
      • 根據左右元素總量關系創建關系式
      • 求解各個化學物質之間的比例關系
    • 取比例組最小公倍數為化學物質系數
  • 總代碼
  • 結束語

前言

在幾天前無意中看到了有這么一個 bce 庫,能夠平衡化學方程式系數,我就想著這不就是配配元素嘛,自己按看到的例子進行嘗試,結果…
程序設計上越來越復雜,也不知道他那 bce-console.exe 僅僅 104KB 大小的程序怎么就能如此迅速配平化學方程(可能比較懶,所以像后面電子守恒和未知數關系的我就沒有去研究如何做對應的解決方案)。

例子

>> P+O2=P2O5 4P+5O2=2P2O5 >> H2O(g)+Fe=Fe3O4+H2 4H2O(g)+3Fe=Fe3O4+4H2 >> CO+Fe2O3=Fe+CO2 3CO+Fe2O3=2Fe+3CO2 >> C2H5OH+O2=CO2+H2O C2H5OH+3O2=2CO2+3H2O >> Cl2+<e->=Cl<e-> Cl2+2<e->=2Cl<e-> >> Cu+Fe<3e+>=Cu<2e+>+Fe<2e+> Cu+2Fe<3e+>=Cu<2e+>+2Fe<2e+> >> LiOH+H2O2+H2O=Li2O2.H2O2.3H2O 2LiOH+2H2O2+H2O=Li2O2.H2O2.3H2O >> C{n}H{2n+2}+O2=CO2+H2O {(n+1)^(-1)}C{n}H{2*n+2}+{(1/2)*(3*n+1)/(n+1)}O2={n/(n+1)}CO2+H2O >> CH3(CHCH){n}CH3+Cl2=CH3(CHClCHCl){n}CH3 CH3(CHCH){n}CH3+{n}Cl2=CH3(CHClCHCl){n}CH3 >> X-<e->=X<{n}e+> X-{n}<e->=X<{n}e+> >> CH4;HCN;NH3;O2;H2O 2HCN+6H2O=2CH4+2NH3+3O2 >> CH4(g);HCN(g);NH3(g);O2(g);H2O(g) 2CH4(g)+2NH3(g)+3O2(g)=2HCN(g)+6H2O(g)

運行截圖

bce-console.exe運行結果(pip install bce安裝)

總程序運行結果

需要的庫

import re # 正則表達式庫,用于提取元素和數目 import string # 獲取所有空白字符,替換掉化學方程式中多余空白字符以防出現意外 from sympy import solve, symbols # 用于解方程的庫,solve是求解函數,symbols可以生成符號變量

步驟

這里采用等式左右兩邊所有化學元素數量種類守恒的方式來解決配平問題。

拆分等式左右側

由于本文不考慮其他守恒規則,所以先過濾掉其他規則的化學方程式(最后只剩下例子的前4個)。
這里的 left 和 right 就是化學方程式等號左右兩邊的內容。

if '=' not in ChemicalEquations and ';' in ChemicalEquations:all_items = ChemicalEquations.split(';')pass # 自動化合價計算等式先不做,先做元素配平 elif 'e+>' in ChemicalEquations or 'e->' in ChemicalEquations or '{' in ChemicalEquations or '.' in ChemicalEquations:pass # 暫時不搞電子<e+>/<e->和含./{n}的化學物質等的運算 else:left, right = ChemicalEquations.split('=')

拆分每個化學物質和±號

化學物質組成

欲獲得化學物質,首先得知道有哪些化學元素符號。
當然這邊的化學物質是包括電子和未知數倍數關系提取的,所以很長。
這結果并不是完全只有化學物質,還包括了化學物質后的 ± 號,雖然沒有電子參與一般都是 + 號。

1、倍數元素:\d|{[A-Za-z0-9+-]} 2、電荷元素:<(?:\d|{[A-Za-z0-9+-]})?e[+-]> 3、化學元素:[A-Z][a-z]?\.? 4、物質狀態:\([gls]\) # g是氣體,l是液體,s是固體 5、化學物質:[+-]?(<(?:\d+|{[A-Za-z0-9+-]+})?e[+-]>|(?:(?:\(?(?:[A-Z][a-z]?\.?)+(?:\d+|{[A-Za-z0-9+-]+})?\)?)+(?:<(?:\d+|{[A-Za-z0-9+-]+})?e[+-]>)?)+)(?:\([gls]\))?([+-]?) 6[]物質:[+-]?(<(?:\d+|{[A-Za-z0-9+-]+})?e[+-]>|(?:[A-Za-z0-9.]+(?:\([A-Za-z0-9]+\))?(?:{[A-Za-z0-9+-]+})?(?:<(?:\d+|{[A-Za-z0-9+-]+})?e[+-]>)?)+)(?:\([gls]\))?([+-]?)

化學物質提取

left, right = ChemicalEquations.split('=') items = re.compile(R'[+-]?(<(?:\d+|{[A-Za-z0-9+-]+})?e[+-]>|(?:(?:\(?(?:[A-Z][a-z]?\.?)+(?:\d+|{[A-Za-z0-9+-]+})?\)?)+(?:<(?:\d+|{[A-Za-z0-9+-]+})?e[+-]>)?)+)(?:\([gls]\))?([+-]?)') left_items, right_items = items.findall(left), items.findall(right)

到這里所有化學物質和運算符 ± 就全部被提取出來了,如何用一行代碼讓他們從二層列表中脫出來到一層列表呢?用萬能的匿名表達式就能實現

get_all = lambda _, __ = eval("[]"): __.clear() or [[__.append(____) for ____ in ___ if ____] for ___ in _] and __

這里為什么要用 __ = eval("[]") 而不用 __ = [] 或 __ = list() 呢?這里先簡單的解釋一下 python 是怎么幫我們把值賦給變量的:
python會把同一值所在地址賦值給變量,也就是說,兩個不同變量名賦值同一值,他們的內存地址相同【id(XXX)相同】。所以這邊如果賦值為空列表,那會干擾其他同時運行的空列表,所以使用空列表作為默認參數會有問題,解釋器會報凸顯的黃色,而使用 eval("[]") 計算出的列表就不會報黃警告,雖然這也是空列表,不過為了避免多次執行出現的變量意外,我在使用前執行了 list..clear() 來清空列表,這樣最后得到的結果只會有后面執行的。然后 or 后面的列表并不是需要的結果,只是借助了列表施展列表推導式,在推導式中為列表變量添加值,最后用 and 變量將提取出元素的列表值傳回去。

統計每個化學物質內每個化學元素的數量

判斷等式雙方元素種類是否一致

這里的 ELEMENT 是用來提取出所有化學元素包括電子的。
這里為什么不直接用 assert elements == right_elements 呢?因為列表是有序的,只要順序不一樣列表就不一樣,這里只需要種類一致,所以采用集合相等,或集合反交集為空來判斷兩邊元素種類是否一致。

ELEMENT = re.compile(R'([A-Z][a-z]?\.?|<(?:\d|{[A-Za-z0-9+-]})?e[+-]>)') elements = list(set(get_all([ELEMENT.findall(item) for item in left_item_list if item not in list('+-')]))) right_elements = list(set(get_all([ELEMENT.findall(item) for item in right_item_list if item not in list('+-')]))) # assert not (set(elements) ^ set(right_elements)), '化學方程式兩方元素不守恒!' assert set(elements) == set(right_elements), '化學方程式兩方元素不守恒!'

計算左右雙方元素數量,獲取每個元素在每個物質中的占比

接下來就是統計左右元素數量,scale_group 用于獲取每個元素在不同物質中的數量,left_item_dict 和 right_item_dict 用于獲取每個物質中每個元素的數量,先以物質鍵中獲取元素數量,再反轉以元素為鍵,獲取元素在不同物質中的數量。

scale_group = {element: {} for element in elements} left_item_dict = {item: {} for item in left_item_list if item not in list('+-')} right_item_dict = {item: {} for item in right_item_list if item not in list('+-')} for item_list, item_dict in ((left_item_list, left_item_dict), (right_item_list, right_item_dict)):for item in item_list:if item not in list('+-'):for element in re.compile(R'([A-Z][a-z]?)(\d*)').findall(item):if element[0] not in item_dict[item]:item_dict[item][element[0]] = 0item_dict[item][element[0]] += element[1].isdigit() and int(element[1]) or 1 for element in elements:for item_dict in (left_item_dict, right_item_dict):for item in item_dict:if element in item:scale_group[element][item] = item_dict[item][element]

解化學元素守恒方程

按物質名稱創建符號變量

symbols_list = symbols([item for item in (left_item_list + right_item_list) if item not in list('+-')], positive=True, integer=True, real=True) # 為每個化學物質創建元素符號 for symbol in symbols_list:globals()[str(symbol)] = symbol # 將符號變量釋放到全局,為下文eval()字符串轉變量算式做基礎

根據左右元素總量關系創建關系式

關系為:每個元素中,左邊元素數量之和 - 右邊元素數量之和 = 0。
eval(temp_str) 是為了將字符串計算成符號變量方程

solve_list = [] for element in elements:temp_str = ''temp = []for item in left_item_dict:index = scale_group[element].get(str(item), if index:temp.append(f'{index}*{str(item)}')temp_str += '+'.join(temp)temp = []for item in right_item_dict:index = scale_group[element].get(str(item), if index:temp.append(f'{index}*{str(item)}')if temp:temp_str += '-' + '-'.join(temp)solve_list.append(eval(temp_str))

求解各個化學物質之間的比例關系

res 為各個化學物質系數之間比例關系的解:{其他化學物質:n * 某化學物質}
can_zhao 為作為參照的化學物質,通過每個比例除以它得到純數字比例,并將它設為1,就得到了他們之間的數字比例關系。
觀察到一般 slove 求解的關系比例分子已經是最小公倍數,而且分母只會有一個數,所以此處將分母提取出來讓所有比例數字乘以分母,得到最小公倍數系數比例組。

res = solve(solve_list, symbols_list) can_zhao = [item for item in symbols_list if str(item) == list(set(list(left_item_dict.keys()) + list(right_item_dict.keys())) - set(list(map(str, res.keys()))))[0]][0] for item in res:res[item] /= can_zhao res[can_zhao] = 1 fen_mu = re.compile(R'/(\d+)?').findall(str(res)) if fen_mu:bs = int(fen_mu[0])for item in res:res[item] *= bs

取比例組最小公倍數為化學物質系數

生成配平的化學方程式,chemical_equations 就是需要的配平后的化學方程式

chemical_equations = [] for item_dict in (left_item_dict, right_item_dict):all_item = []all_index = []for item in item_dict:all_item.append(item)all_index.append(res[[i for i in symbols_list if str(i) == item][0]])chemical_equations.append(' + '.join([f'{"" if all_index[i] == 1 else all_index[i]}{all_item[i]}' for i in range(len(item_dict))])) chemical_equations = ' = '.join(chemical_equations)

總代碼

# _*_ coding:utf-8 _*_ # Project: 最最最沒用程序合集 # FileName: AutoBalancingChemicalEquations.py # UserName: user_from_future博主 # ComputerUser:user_from_future # Day: 2022/2/21 # Time: 20:21 # IDE: PyCharm # 2022年,所有bug都將會被丟到海里喂鯊魚!我說的!不容反駁!# 自動配平化學方程式 # import bceimport re import string from sympy import solve, symbols""" 邏輯流程: 1、拆分等式左右側 2、拆分每個化學物質和+-號 3、統計每個化學物質內每個化學元素的數量 4、解化學元素守恒方程 5、取比例組最小公倍數為化學物質系數 元素特征: 1、倍數元素:\d|{[A-Za-z0-9+-]} 2、電荷元素:<(?:\d|{[A-Za-z0-9+-]})?e[+-]> 3、化學元素:[A-Z][a-z]?\.? 4、物質狀態:\([gls]\) # g是氣體,l是液體,s是固體 5、化學物質:[+-]?(<(?:\d+|{[A-Za-z0-9+-]+})?e[+-]>|(?:(?:\(?(?:[A-Z][a-z]?\.?)+(?:\d+|{[A-Za-z0-9+-]+})?\)?)+(?:<(?:\d+|{[A-Za-z0-9+-]+})?e[+-]>)?)+)(?:\([gls]\))?([+-]?) 6、[②]物質:[+-]?(<(?:\d+|{[A-Za-z0-9+-]+})?e[+-]>|(?:[A-Za-z0-9.]+(?:\([A-Za-z0-9]+\))?(?:{[A-Za-z0-9+-]+})?(?:<(?:\d+|{[A-Za-z0-9+-]+})?e[+-]>)?)+)(?:\([gls]\))?([+-]?)試驗過程: >> P+O2=P2O5 4P+5O2=2P2O5 >> H2O(g)+Fe=Fe3O4+H2 4H2O(g)+3Fe=Fe3O4+4H2 >> CO+Fe2O3=Fe+CO2 3CO+Fe2O3=2Fe+3CO2 >> C2H5OH+O2=CO2+H2O C2H5OH+3O2=2CO2+3H2O >> Cl2+<e->=Cl<e-> Cl2+2<e->=2Cl<e-> >> Cu+Fe<3e+>=Cu<2e+>+Fe<2e+> Cu+2Fe<3e+>=Cu<2e+>+2Fe<2e+> >> LiOH+H2O2+H2O=Li2O2.H2O2.3H2O 2LiOH+2H2O2+H2O=Li2O2.H2O2.3H2O >> C{n}H{2n+2}+O2=CO2+H2O {(n+1)^(-1)}C{n}H{2*n+2}+{(1/2)*(3*n+1)/(n+1)}O2={n/(n+1)}CO2+H2O >> CH3(CHCH){n}CH3+Cl2=CH3(CHClCHCl){n}CH3 CH3(CHCH){n}CH3+{n}Cl2=CH3(CHClCHCl){n}CH3 >> X-<e->=X<{n}e+> X-{n}<e->=X<{n}e+> >> CH4;HCN;NH3;O2;H2O 2HCN+6H2O=2CH4+2NH3+3O2 >> CH4(g);HCN(g);NH3(g);O2(g);H2O(g) 2CH4(g)+2NH3(g)+3O2(g)=2HCN(g)+6H2O(g) """ChemicalEquationsList = ['P+O2=P2O5', # 4P+5O2+2P2O5'H2O(g)+Fe=Fe3O4+H2', # 4H2O(g)+3Fe=Fe3O4+4H2'CO+Fe2O3=Fe+CO2', # 3CO+Fe2O3=2Fe+3CO2'C2H5OH+O2=CO2+H2O', # C2H5OH+3O2=2CO2+3H2O'Cl2+<e->=Cl<e->', # Cl2+2<e->=2Cl<e->'Cu+Fe<3e+>=Cu<2e+>+Fe<2e+>', # Cu+2Fe<3e+>=Cu<2e+>+2Fe<2e+>'LiOH+H2O2+H2O=Li2O2.H2O2.3H2O', # 2LiOH+2H2O2+H2O=Li2O2.H2O2.3H2O'C{n}H{2n+2}+O2=CO2+H2O', # {(n+1)^(-1)}C{n}H{2*n+2}+{(1/2)*(3*n+1)/(n+1)}O2={n/(n+1)}CO2+H2O'CH3(CHCH){n}CH3+Cl2=CH3(CHClCHCl){n}CH3', # CH3(CHCH){n}CH3+{n}Cl2=CH3(CHClCHCl){n}CH3'X-<e->=X<{n}e+>', # X-{n}<e->=X<{n}e+>'CH4;HCN;NH3;O2;H2O', # 2HCN+6H2O=2CH4+2NH3+3O2'CH4(g);HCN(g);NH3(g);O2(g);H2O(g)', # 2CH4(g)+2NH3(g)+3O2(g)=2HCN(g)+6H2O(g) ]ELEMENT = re.compile(R'([A-Z][a-z]?|<(?:\d|{[A-Za-z0-9+-]})?e[+-]>)')def max_gys(num1, num2): # 兩個數最大公約數while num2:temp = num1 % num2num1, num2 = num2, tempreturn num1def min_gbs(num1, num2): # 兩個數最小公倍數return num1 * num2 // max_gys(num1, num2)# 將二層列表中的內容轉成一層列表 get_all = lambda _, __ = eval("[]"): __.clear() or [[__.append(____) for ____ in ___ if ____] for ___ in _] and __def handle_double_elements_list_scale(element1, element2, chemicals, scale_group): # 同步兩個元素組中相同的元素shared = list(set(chemicals[element1]) & set(chemicals[element2]))if shared:multiply = min_gbs(scale_group[element1][shared[0]], scale_group[element2][shared[0]])shared1 = scale_group[element1][shared[0]]for item in scale_group[element1]:scale_group[element1][item] *= (multiply // shared1)shared2 = scale_group[element2][shared[0]]for item in scale_group[element2]:scale_group[element2][item] *= (multiply // shared2)return element2def calc_equations(left_item_list, right_item_list):elements = list(set(get_all([ELEMENT.findall(item) for item in left_item_list if item not in list('+-')])))right_elements = list(set(get_all([ELEMENT.findall(item) for item in right_item_list if item not in list('+-')])))assert set(elements) == set(right_elements), '化學方程式兩方元素不守恒!'symbols_list = symbols([item for item in (left_item_list + right_item_list) if item not in list('+-')], positive=True, integer=True, real=True) # 為每個化學物質創建元素符號for symbol in symbols_list:globals()[str(symbol)] = symbol # 將符號變量釋放到全局,為下文eval()字符串轉變量算式做基礎scale_group = {element: {} for element in elements}left_item_dict = {item: {} for item in left_item_list if item not in list('+-')}right_item_dict = {item: {} for item in right_item_list if item not in list('+-')}for item_list, item_dict in ((left_item_list, left_item_dict), (right_item_list, right_item_dict)):for item in item_list:if item not in list('+-'):for element in re.compile(R'([A-Z][a-z]?)(\d*)').findall(item):if element[0] not in item_dict[item]:item_dict[item][element[0]] = 0item_dict[item][element[0]] += element[1].isdigit() and int(element[1]) or 1for element in elements:for item_dict in (left_item_dict, right_item_dict):for item in item_dict:if element in item:scale_group[element][item] = item_dict[item][element]solve_list = []for element in elements:temp_str = ''temp = []for item in left_item_dict:index = scale_group[element].get(str(item), "")if index:temp.append(f'{index}*{str(item)}')temp_str += '+'.join(temp)temp = []for item in right_item_dict:index = scale_group[element].get(str(item), "")if index:temp.append(f'{index}*{str(item)}')if temp:temp_str += '-' + '-'.join(temp)solve_list.append(eval(temp_str))res = solve(solve_list, symbols_list)can_zhao = [item for item in symbols_list if str(item) == list(set(list(left_item_dict.keys()) + list(right_item_dict.keys())) - set(list(map(str, res.keys()))))[0]][0]for item in res:res[item] /= can_zhaores[can_zhao] = 1fen_mu = re.compile(R'/(\d+)?').findall(str(res))if fen_mu:bs = int(fen_mu[0])for item in res:res[item] *= bschemical_equations = []for item_dict in (left_item_dict, right_item_dict):all_item = []all_index = []for item in item_dict:all_item.append(item)all_index.append(res[[i for i in symbols_list if str(i) == item][0]])chemical_equations.append(' + '.join([f'{"" if all_index[i] == 1 else all_index[i]}{all_item[i]}' for i in range(len(item_dict))]))chemical_equations = ' = '.join(chemical_equations)return chemical_equationsfor ChemicalEquations in ChemicalEquationsList:for space in string.whitespace:ChemicalEquations = ChemicalEquations.replace(space, '')if '=' not in ChemicalEquations and ';' in ChemicalEquations:all_items = ChemicalEquations.split(';')pass # 自動化合價計算等式先不做,先做元素配平elif 'e+>' in ChemicalEquations or 'e->' in ChemicalEquations or '{' in ChemicalEquations or '.' in ChemicalEquations:pass # 暫時不搞電子<e+>/<e->和含./{n}的化學物質等的運算else:left, right = ChemicalEquations.split('=')items = re.compile(R'[+-]?(<(?:\d+|{[A-Za-z0-9+-]+})?e[+-]>|(?:(?:\(?(?:[A-Z][a-z]?\.?)+(?:\d+|{[A-Za-z0-9+-]+})?\)?)+(?:<(?:\d+|{[A-Za-z0-9+-]+})?e[+-]>)?)+)(?:\([gls]\))?([+-]?)')left_items, right_items = items.findall(left), items.findall(right)print(ChemicalEquations + '\n\t' + calc_equations(list(get_all(left_items)), list(get_all(right_items))))

結束語

當然了,我這個只能解決沒有電子轉移和沒有未知數關系的方程式,剩余的比較懶沒想做,有興趣的可以完善我這個程序哦~
想要標準的化學方程式配平結果,請安裝 bce 庫,使用 bce-console.exe 程序求解配平。
幾天后可能就要手術去了,屆時我將不能及時回復各個評論。作為第一個也是最后一個不正緊的打算,就像這樣隨意嘗試一下,最后得出結論:程序員還是搬運代碼來的香~ (前人的知識就是現人的工具)

總結

以上是生活随笔為你收集整理的史上最最最没用程序——自写平衡化学方程式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。