化学反応分解 (3回目)
正規表現はある程度に切り上げて,とりあえず処理できる形を作ってみました。
プログラマーではないので行き当たりばったりでやってますが,なんとなく動いているようです。
Microsoft VBScripting Runtime と Microsoft VBScript Regular Expressions 5.5への参照設定を前提としています。
Sub 化学反応式分解() Dim Reg As RegExp, Matches As MatchCollection, SMatches As SubMatches Set Reg = New RegExp Dim 化学反応式 As String 化学反応式 = "4NaHCO3→2Na2CO3+2H2O+2CO2" With Reg .Global = True .Pattern = "([\+→])|([A-Z][a-z]?)|([0-9]*)" Set Matches = .Execute("+" & 化学反応式 & "+") End With Dim i, j, Col As New Collection For i = 0 To Matches.Count - 3 Col.Add Matches(i).Value If IsNumeric(Matches(i)) = False And IsNumeric(Matches(i + 1)) = False Then Col.Add "1" Next Dim 反応物 As New Dictionary, 生成物 As New Dictionary, flg矢印 As Boolean, 係数 As Long, Col係数 As New Collection For i = 1 To Col.Count Step 2 Select Case Col(i) Case Is = "+" 係数 = CLng(Col(i + 1)) Col係数.Add 係数 Case Is = "→" 係数 = CLng(Col(i + 1)) Col係数.Add 係数 flg矢印 = True Case Else If flg矢印 = True Then 生成物(Col(i)) = 生成物(Col(i)) + CLng(Col(i + 1)) * 係数 Else 反応物(Col(i)) = 反応物(Col(i)) + CLng(Col(i + 1)) * 係数 End If End Select Next Dim 総数判定 As Boolean '反応物と生成物の係数の比較 総数判定 = True For i = 0 To 反応物.Count - 1 'Debug.Print 反応物.Keys()(i) & " " & 反応物(反応物.Keys()(i)) & "," & 生成物(反応物.Keys()(i)) If 反応物(反応物.Keys()(i)) <> 生成物(反応物.Keys()(i)) Then 総数判定 = False Next '公約数があるかどうか確認 Dim flg As Boolean, 公約数判定 As Boolean, k, dic公約数 As New Dictionary 公約数判定 = True For i = 1 To Col係数.Count If Col係数(i) <> 1 Then For j = Col係数(i) To 2 Step -1 If Col係数(i) Mod j = 0 Then flg = True For Each k In Col係数 If k Mod j <> 0 Then flg = False Next If flg = True Then 公約数判定 = False dic公約数(j) = 1 End If End If Next End If Next Dim 公約数列挙 As String For i = 0 To dic公約数.Count - 1 公約数列挙 = 公約数列挙 & "," & dic公約数.Keys()(i) Next If 公約数判定 = False Then 公約数列挙 = Mid(公約数列挙, 2) MsgBox "総数判定は" & 総数判定 & ",公約数は" & Switch(公約数判定 = False, 公約数列挙, 公約数判定 = True, "ありません。") If 公約数判定 = True And 総数判定 = True Then MsgBox "この係数は妥当です" Else MsgBox "この係数は不適です" Stop End Sub
これを実行すると,
こんな感じで何か言ってくるんですが,何をやっているのかというと,
化学反応式 = "4NaHCO3→2Na2CO3+2H2O+2CO2"
化学反応式のところに書いている化学反応式が妥当かどうかを判断させています。
まず,正規表現でばらっばらにして,
係数や添え字が1の時は省略されたりするので,等間隔で扱えるように整えます。
元はこれで,
4NaHCO3→2Na2CO3+2H2O+2CO2
内部ではこんな感じ
+4Na1H1C1O3→2Na2C1O3+2H2O1+2C1O2
まず1文字目に+を入れて,+か→があると物質のスタートだという合図。
係数は今は入ってますが,係数がなければ1をつけます。
各元素の直後の1が省略されててもつけるようにすることで,作業をしやすくしました。
文字数は決まっていないのでコレクションオブジェクトに放り込んでいます。
その後,Dictionaryオブジェクトを利用することで,各元素の数値を格納する。
キーに元素記号を使っているので,各元素ごとの合計の比較を容易にしています。
また,係数に公約数が含まれるかどうかを今回はきちんと処理をしました。
たぶんこれで化学反応式を与えるだけで,係数や各元素の数を把握し,その係数が適切かどうかを判断できていると思います。
作ろうとしているやつは,化学反応式の導入部分で使用する予定のもののため,括弧を含む面倒なやつは今回は想定していません。
けっこうごちゃごちゃいろんなことをやっている割には正規表現とDirectoryオブジェクトのおかげで短くできているんじゃないかなぁと思います。
とりあえず一歩進んだ ( ´ー`)フゥー...