読者です 読者をやめる 読者になる 読者になる

Powerpoint VBAを使おう!

Powerpoint VBAやExcelのVBAで遊んでいます。Word VBAも始めました。

VBAに興味を持たれた方に私見を書きます。

さて,thomさんの記事を読んでいて,自分のことを少し思い出したり思い当たるところも多々あるので,少し書きます。

thom.hateblo.jp
thom.hateblo.jp

前提として,

わたしの特性はけっこう偏っていまして,記憶力がとにかく極端にありません。
忘れるのを超えるスピードで知識を塗り重ねるしかない,とても残念なところがあります。

極めて方向音痴で,しかも一貫性のない行動をします。
妻と買い物に行くときになんでそっちに行くの?とよく言われます。そういえばそうだねとUターンしないといけないこともよくあります(;´▽`A``
何年も同じところに住んでいて,毎週一緒に買い物に行くのに,同じ行動を取らないんです。不思議な人間だと自覚しています。

高校の教員という仕事をしていますが,とにかく日々何度も同じ内容を教えるからこそ,その分野の知識を保ちますが,やっていないところなどものすごいスピードで忘れるんです。
でも,大事なことは,また塗り重ねるという行動や,その自分の欠点を補うために準備を怠らないようにすること。
教材をきちんと作ろうとしたり,新しい表現はできないか取り組める点はあります。

そして,教育もデジタル化が加味される時代になり,タブレットが教育の世界に登場するようになりました。私にとって生き易い環境がやってきたことになります。
準備が授業に直結しやすくなったんです。準備は大変ですがその分効果につながります。

そして,さらにその準備を補うために日々いろいろなVBAでのプログラミング,Word,Excel,Powerpointの素の機能への細かい部分へのチェックをし続けています。
このブログはまさに備忘録なんです。残しておかないととにかく忘れますので。。


さて,こういうとても残念な部分を持つ私ですが,読めばわかるさ,やってみればわかるさという根拠のない自信もとりえなので,わからない本を何度でも読めるんですね。頭イテーとか言いながら意味がわからないままでもある程度読み進めます。

そして,一度や二度読んだだけでわかるわけないさ,一度読んだだけでわかる人間ってのは天才の部類だよ,といつも子供たちにも言いますので,わからないことを苦にしていません。

概念というものはとても大事で,それをつかまないとなかなか細かいところがわかりません。

でも,概念というのは切り口が変わると表現が変わります。部分にクローズアップすると,他とは別の表現になったりするとても複雑なもの。

そんな難しいものですが,人間の頭もとてもすごくて,何度も 何度も 読んだり取り組むうちに少しずつ頭の中で知識や破片が確実に積もっていって,やがてそれらがつながっていって,ある程度を超えると理解できた!ってなるものだと思うんです。一度や二度わからないのはあたりまえ。でも何度も読んだり書いたりしているとなぜか不思議とわかるようになるよって言いたいわけです。

今でこそ使いにくいなーと思ったオブジェクトなどはクラスモジュールでラップして,自分が使いやすいように,つくりかえるようになりました。

わたしのブログには,証拠が残っていますが,クラスモジュールって何ですか?という人間でした。

コレクションオブジェクトって何ですか?という人間でした。

パワーポイントのマクロとか記録できないのにできるわけないやん,という人間でした。

そういう状態が昨年の11月で,数ヶ月,とにかく忙しい状況でもあったんですが,やるよ,と決めて後に引かないようにブログとして公の場に公言し続けることで前に進む,取り組む,本を読む,助言をそのたびに検証する,と続けた結果,今ではとりあえず思うことはそれなりに実現できる状態となりました。


何が言いたいかというと,

何度もわからないなりに読む,プログラムを書く,そういうことをしていると,わかってはいなくても頭に知識や概念のかけらが残っていきます。

そして,私たちの脳はそれをつながったイメージに作り上げていく機能を持っていてくれています。

あきらめずに真似をする,質問をする,間違ってもいいからやってみて,こう書いたんだけどだめでしたとアピールしてみる。

そしたら誰か助けてくれますし,パズルを解くようにこのやり取りは楽しいですし,何より仕事上の力になると思われます。

残念ながら,職場ではVBAの面では助けてくれる人はなかなか出会えませんが,地力がつけば,そこは一人で解決できますし,正直他人のために組んであげる必要はわたしも無いと思っています。

仕事上責任をもって職務を遂行するためには,ブラックボックスのまま他人の組んだものなど使ってられません。怖くて。

それは自分に対しても徹底すべきですが,他人に対してもそうあるべきだと思います。

引き継げないという前提で,マクロが無くてもやれるように道を残しておいて,マクロも残しておくからやる気があるなら読み解いて自分のものにして使ってね,というスタンスで仕事をしています。

プログラミングも教育の世界に入り込んできつつありますので,今よりはもっと組める人がたくさんそのうち出てくるんでしょうけど今しばらくは変わらないのかな。

その間は自分の武器として,でも自分を傷つける武器にはならないように運用方法には気を付けながら恩恵だけ預かるように日々すごしています。

ただ,私はVBAなしで仕事しろと言われると正直ぞっとします。

そのくらい便利なものです。

状況を激変させられる力をたまに持っています。

なので,すごそうだなぁと思われた方はめげずにぜひやられてみることをお勧めしたいと思っています。

正規表現5回目くらい

化学式の分解,まだやっています。
Replaceメソッドと戯れているところ。想定通りの動きをさせられません。

Replaceメソッドを以前載せたものに加えたうえで,挙動を載せてみます。

Word,Excel,Powerpoint どれでも動きます。
WordはNormalテンプレートが邪魔なので,ExcelかPowerpointでの実行がおすすめかなぁ。

実行結果

コードは後で載せます。

必要な部分だけピックアップしますが,複塩の化学式を試しに使いました。括弧が複雑に入っています。

※化学式の(NH4)3の部分は本来は(NH4)2だったんですが,Replaceの機能を確認するためにわざと(NH4)3にしています。

ChemicalString = "(NH4)3Fe(SO4)2・6H2O "

RE.Pattern_ = "\((.+?)\)([0-9]+)"

f:id:chemiphys:20170312215906p:plain
捉えたい情報はしっかりとれています。

でも,これに次のようにReplaceメソッドを使うと,

?RE.Replace_(ChemicalString, "$1$1")
↓
NH4NH4FeSO4SO4・6H2O 
?RE.Replace_(ChemicalString, "$1$2")
↓
NH43FeSO42・6H2O 

と出力します。上記のように,イミディエイトウィンドウに Replace_メソッドを直接かけるので,いろいろチェックは簡単です。(Public様々)

それぞればらばらにちゃんと取得できているのに,別々に置換設定できない。
できないというか,やり方がわからない・・

とても面白い挙動はしていますけど・・。せっかくクラスモジュールでラップしたので,自分好みのReplace2メソッドを実装するほうがいいのかな(ΦωΦ)

その辺好き勝手できるのがクラスモジュールのいいところですね。

今は元の機能をあまり変えたくない,メソッド名なども極力変えたくないという気持ちがあるので,これ以上はいじりませんが,今度本格的に化学反応式を好き勝手に分解して利用するときには,完全に自分仕様のクラスモジュールに書き換えていきたいと思います。

正規表現モジュールとはけっこう楽しく遊べました。また,近いうちに扱いたいと思います。

コードを載せておきます。

標準モジュール

Option Explicit

Public RE As RegExpClass

Sub test()
Set RE = New RegExpClass

Dim ChemicalString As String
ChemicalString = "(NH4)3Fe(SO4)2・6H2O "
RE.sourceString_ = ChemicalString
RE.Pattern_ = "\((.+?)\)([0-9]+)"

Debug.Print RE.Execute_

Debug.Print RE.Replace_(ChemicalString, "$1$1")

End Sub

クラスモジュール


RegExpClass.cls

Option Explicit

Private pPattern As String
Private pIgnoreCase As Boolean
Private pGlobal As Boolean
Private pSourceString As String
Private pMatchCollection As Object
Private pSubMatches As Variant

Property Let Pattern_(Optional argIgnoreCase As Boolean = False, Optional argGlobal As Boolean = True, argPattern As String)
    pPattern = argPattern
    pIgnoreCase = argIgnoreCase
    pGlobal = argGlobal
End Property

Property Let IgnoreCase_(argIgnoreCase_ As Boolean)
    pIgnoreCase = argIgnoreCase
End Property
Property Get IgnoreCase_() As Boolean
    IgnoreCase_ = pIgnoreCase
End Property

Property Let Global_(argGlobal As Boolean)
    pGlobal = argGlobal
End Property
Property Get Global_() As Boolean
    Global_ = pGlobal
End Property

Property Let sourceString_(argSourceString As String)
    pSourceString = argSourceString
End Property
Property Get sourceString_() As String
    sourceString_ = pSourceString
End Property

Property Get MatchCollection_() As Object
    Set MatchCollection_ = pMatchCollection
End Property

Property Get SubMatches_() As Variant
    SubMatches_ = pSubMatches
End Property

Function Execute_() As String
    On Error GoTo Err:
    Dim ret As String
    
    'Dim Regex As VBScript_RegExp_55.RegExp
    'Set Regex = New VBScript_RegExp_55.RegExp
    Dim Regex As Object
    Set Regex = CreateObject("VBScript.RegExp")
    
    
    With Regex
        .Pattern = pPattern
        .IgnoreCase = pIgnoreCase
        .Global = pGlobal
        Set pMatchCollection = .Execute(pSourceString)
    End With
    
    Dim s
    
    For Each s In pMatchCollection
        ret = ret & "," & IIf(s = "", Chr(34) & Chr(34), s)
    Next
    Execute_ = pMatchCollection.Count & "個Hit" & vbCrLf & Mid(ret, 2)
    
    If pMatchCollection.Count = 0 Or pMatchCollection(0).SubMatches.Count = 0 Then
        Erase pSubMatches
        Exit Function
    End If
    
    ReDim pSubMatches(0 To pMatchCollection.Count - 1, 0 To pMatchCollection(0).SubMatches.Count - 1) As String
    Dim i As Long: i = 0
    Dim j As Long
    Dim s2
    For Each s In pMatchCollection
        j = 0
        For Each s2 In s.SubMatches
            pSubMatches(i, j) = s2
            j = j + 1
        Next
        i = i + 1
    Next
    Exit Function
Err:
Call ErrMsg(Err)
End Function

Sub ErrMsg(argErr As Long)
    Select Case argErr
        Case 5017
            MsgBox ("アプリケーション定義またはオブジェクト定義エラーです。" & Chr(10) & _
            "正規表現部分の文法を見直してみてください。")
    End Select
End Sub

Function Replace_(argSourceString As String, argReplaceVar As Variant) As String
    On Error GoTo Err:
    Dim ret As String
    
    'Dim Regex As VBScript_RegExp_55.RegExp
    'Set Regex = New VBScript_RegExp_55.RegExp
    Dim Regex As Object
    Set Regex = CreateObject("VBScript.RegExp")
    
    
    With Regex
        .Pattern = pPattern
        .IgnoreCase = pIgnoreCase
        .Global = pGlobal
    End With

    Replace_ = Regex.Replace(argSourceString, argReplaceVar)
Exit Function
Err:
Call ErrMsg(Err)

End Function

早く正規表現から抜け出さないとな。。

クラス作ってからすこしやりやすくなりました。

二冊の本で正規表現の学習を進めているんですが,

詳説 正規表現 第3版

詳説 正規表現 第3版

  • 作者: Jeffrey E.F. Friedl,株式会社ロングテール,長尾高弘
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2008/04/26
  • メディア: 大型本
  • 購入: 24人 クリック: 754回
  • この商品を含むブログ (86件) を見る
こちらの本の第1・2章は読んでよかったと思います。というか,その後の章は私は頭が拒否します。
もっと詳しく,または熟練したら読めるようになるのかな。。現状無理。

反復学習ソフト付き 正規表現書き方ドリル (WEB+DB PRESS plus)

反復学習ソフト付き 正規表現書き方ドリル (WEB+DB PRESS plus)

こちらの本は上記の本よりはとても易しく読めます。でも,やはり上記の本を先に読んだ方がいいと思えます。
さらさら頭に入ってきます。

で,やはり主の課題は私は化学反応式の分解なんです。
()をどうしようかなぁというのをとにかく漠然ととらえつつ不安を抱えたまま進んでいたんですが,

簡単ですね。

Al2(SO4)3 とかありますけど, Al2SO4SO4SO4 とかに置換すればいいだけですね。括弧の中身と括弧直後の数字を読み取れば,これは可能。

通常の方法ならこれも大変なのかもしれませんが,正規表現ならとても簡単。

パターン "\((.+?)\)([0-9]+)"でひっかけると,
f:id:chemiphys:20170312022130p:plain

SubMatchesの中にちゃんと括弧の中身とその直後の数値を捕捉していることがわかります。

ありえない化学式ですが, (NH4)4(CO3)2とかなら
f:id:chemiphys:20170312022401p:plain

こんな感じです。二回ヒットして,それぞれ中身と外の数字を捕捉できています。

前回作ったクラスではReplaceメソッドを実装しわすれていましたので,それを実装することと,エラー処理を実装することが今の課題です。

パターンがおかしいとエラーコード5017を訴えてくるので,それはエラー処理で補足するようにしてあげましょう。一応そっちはもう修正しましたけど・・

replaceまでまとめて実装してから,もう一度記事に載せておくことにします。

あと,文字列を繰り返す部分です。VBAのString関数でできるのかなーと思いましたが,それだけでは無理でした。

二段階でできそうではありますね。String関数では一文字だけなら与えた数値の分繰り返してくれるので,元の文字列に絶対ないような文字をダミーとして数値分の数繰り返したあと,replaceでさらにもう一度ダミー文字を括弧の中身の文字に置き換えてやれば一行で処理を書けるようです。

今日はSubMatchesがちょっと私のいうことを聞いてくれたので,もうちょい読み込めばいけるのかもしれない。

私自身としては,あきらかに理解が進んでいるので,面白くてたまらないんですが,記事としては地味極まりない日々が続いていますので,

早く決着をツケナイトナー(;´▽`A``

VBA全般 正規表現 VBScript.RegExpのクラスモジュール

正規表現の勉強でちょっと停滞気味なので,てこ入れで本を買いました。

反復学習ソフト付き 正規表現書き方ドリル (WEB+DB PRESS plus)

反復学習ソフト付き 正規表現書き方ドリル (WEB+DB PRESS plus)

勉強を進めるにあたり,いちいちコード上で書くのが面倒になりました。

イミディエイトウィンドウでちまちま書きながら試すのはすきなので,いちいち宣言部分や参照設定をしなくてもいいようにラッパークラスみたいなものを作りました。

本題は進んでいませんが,スムーズにやるうえで大事なこと!

WordでもExcelでもPowerpointでも使えるようにしたつもりです。私の環境では使えた。

目次

VBAコード

クラスモジュール

RegExpClass.cls

Option Explicit

Private pPattern As String
Private pIgnoreCase As Boolean
Private pGlobal As Boolean
Private pSourceString As String
Private pMatchCollection As Object
Private pSubMatches As Variant

Property Let Pattern_(Optional argIgnoreCase As Boolean = False, Optional argGlobal As Boolean = True, argPattern As String)
    pPattern = argPattern
    pIgnoreCase = argIgnoreCase
    pGlobal = argGlobal
End Property

Property Let IgnoreCase_(argIgnoreCase_ As Boolean)
    pIgnoreCase = argIgnoreCase
End Property
Property Get IgnoreCase_() As Boolean
    IgnoreCase_ = pIgnoreCase
End Property

Property Let Global_(argGlobal As Boolean)
    pGlobal = argGlobal
End Property
Property Get Global_() As Boolean
    Global_ = pGlobal
End Property

Property Let sourceString_(argsourceString As String)
    pSourceString = argsourceString
End Property
Property Get sourceString_() As String
    sourceString_ = pSourceString
End Property

Property Get MatchCollection_() As Object
    Set MatchCollection_ = pMatchCollection
End Property

Property Get SubMatches_() As Variant
    SubMatches_ = pSubMatches
End Property

Function Execute_() As String
    Dim ret As String
    
    'Dim Regex As VBScript_RegExp_55.RegExp
    'Set Regex = New VBScript_RegExp_55.RegExp
    Dim Regex As Object
    Set Regex = CreateObject("VBScript.RegExp")
    
    
    With Regex
        .Pattern = pPattern
        .IgnoreCase = pIgnoreCase
        .Global = pGlobal
        Set pMatchCollection = .Execute(pSourceString)
    End With
    
    Dim s
    
    For Each s In pMatchCollection
        ret = ret & "," & IIf(s = "", Chr(34) & Chr(34), s)
    Next
    Execute_ = pMatchCollection.Count & "個Hit" & vbCrLf & Mid(ret, 2)
    
    If pMatchCollection.Count = 0 Or pMatchCollection(0).SubMatches.Count = 0 Then
        Erase pSubMatches
        Exit Function
    End If
    
    ReDim pSubMatches(0 To pMatchCollection.Count - 1, 0 To pMatchCollection(0).SubMatches.Count - 1) As String
    Dim i As Long: i = 0
    Dim j As Long
    Dim s2
    For Each s In pMatchCollection
        j = 0
        For Each s2 In s.SubMatches
            pSubMatches(i, j) = s2
            j = j + 1
        Next
        i = i + 1
    Next
    
    
End Function

標準モジュール

Option Explicit

Public RE As RegExpClass

Sub test()
Set RE = New RegExpClass

RE.sourceString_ = "2NaHCO3"
RE.Pattern_ = "(\d)?(\w)*"

Debug.Print RE.Execute_

End Sub

利用方法

標準モジュール内で書いている通り, sourceString_やPattern_を適切に変え,RE.Execute_を実行する,というのが基本の流れです。


Execute_は元とは少し機能を変えており,文字列で検索結果を吐き出させるように変えています。
また,MatchCollectionについてはプロパティとして取得可能にしています。
SubMatchesにアクセスするのはちょっと面倒だったので,配列に入れなおしてSubMatches_プロパティに入れています。Variant型の二次元配列ですが,うまく使えば中身は見れます。
勉強やSubMatchesを利用する練習にするには,文字列で吐き出させるように作り直せばもっといいのかな。簡単に書きなおせると思います。

自分用ではありますが,一度このクラスモジュールをエクスポートしておけば,たぶんVBAが使えるオフィスソフト上では動くかなぁと思われますし,標準モジュール上でPublic宣言をしているので,ある程度の範囲内ではイミディエイトウィンドウ上でパターンや文字列を変更して値を見ることができます。
f:id:chemiphys:20170311225841p:plain

標準モジュールのEnd Subにブレークポイントを設定するかその辺にStopを入れておけば内部変数も見れるので勉強に使えるかな。

さぁ正規表現のほうの勉強にモドラナキャ!(;´▽`A``

(ΦωΦ)

一日更新をやめました。

続きすぎていて,追われる気持ちになるので,昨日は絶対更新しない!という一日でした。

気が楽になった。でも,VBAコードではなく雑記です。

さて,昨日はあいかわらずVBAの正規表現で化学反応式を各原子の数をSubmatchesを利用してできないか,ひたすら悪戦苦闘していました。

うん,うまくいきませんね。。 そろそろ見切りをつけましょう。二段階でスマートにやる,という方向で綺麗に書いて再利用できるようにしよう。

Globalプロパティを理解してなくてしばらく無駄に悩んだり,正規表現オブジェクトも使い方が少し難しいので,喉元過ぎればこんな複雑なのすぐ忘れてしまいます。

備忘録として,いつか記事をしっかり整えて書き残そうと思います。


それと,昨日始めたのに,音の作成の仕方を調べるということがあります。

絵はパワーポイントのオートシェイプを使うレベルではある程度は描ける。あまり上手い必要は無く,意図は伝わるけどどこか稚拙なくらいがいい。

私が狙うあたりはそのへんなのでパワーポイントで描けるレベルで十分です。

ただ,音を作る,というのが全く知識がなく,今まではフリー素材を利用させてもらうだけしか方法はありませんでした。

それはそれでいいんですが,本当にそこはどうすることもできないんだろうか・・となぜかいきなり思い始めまして,調べてみたんです。

フリー素材として他の方が作った音を,著作権表示等きちんとして使わせてもらうのは問題はないんですが,本当にその部分は自作で補えないのか考えたことが無かった。

自分で作ったんだよ,と言いたいときに自分でほとんど作ったけど,音は他の方のだよといいたくないほど頑張って物を作る時もあります。

その時のために身に着けるしかない。


www.bfxr.net
bxfrというフリーソフトに出会いました。音をなんと作れそうです。
f:id:chemiphys:20170311104821p:plain

www.mi7.co.jp
Studio One アカウント登録したら使えるバージョンがあります。すごいっぽい。
f:id:chemiphys:20170311104917p:plain

bxfrのほうで,最初はやろうと思ったんですが,ゲーム用の音って耳に痛いことがあります。

ゲームにはたしかにそういう音が向いていると思う。アクセントとしてはそのくらいがいい。

でも,私の用途は,タイマーの耳障りなくでも聞こえてくる,という音。

それを作るにはStudio Oneのほうかなーと思いました。

VBAだけでもまだまだ手におえていないのに,絵を描いたり,音を作ったりしようなどと,手を広げすぎではありますが,数秒の音を作るくらいのレベルには達することは可能でしょう。

やってみたいと思います。

Powerpoint VBA 上付き文字を少し上げるコード

とても忙しい日々が続いていて,職場ではデータ処理にまたコレクションオブジェクトやthomさん達に教えていただいて作れたソートのコード等を用いてデータ処理をしている日々です。

年度末は大変。。

そうやって忙しい日々を過ごしつつ,次年度のことも近づいてきますので,そちらにも思いを馳せないといけません。

来年度はまた新しいことがやれるのかな。力を蓄えないと,教材も作らないと,いろいろ絵も描かないと,と気はあせるんですが,まったく時間はありません。

コレクションを用いてデータ処理をする方法は抽出やソートを自在にやれ,とても便利なことこの上ありません。

これもきちんと見直したいんですけどね。いろいろ いろいろ 手をだし頭を使い,としているのですでに飽和状態。

いつか整理する時間を取らないといけませんね。。


ネタを考える暇も,正規表現の勉強をする暇もありませんでしたので,かなり以前作ったコードを探してきました。


それは,地味~なコードです。

f:id:chemiphys:20170309222002p:plain

なんの変哲もない,簡単な数式です。みなさんはこの数式を見てどう思われますか?私は若干不服です。

f:id:chemiphys:20170309222507p:plain

違いが伝わりますでしょうか。ちょっと上付き文字が上に上がっているんです。

f:id:chemiphys:20170309222647p:plain
パワーポイントでは,WordやExcelと違い,上付き文字の相対位置が調節できます。

デフォルトは30%です。

わたしの感覚では,ちょっと目立たない。職業的に指数なのかそうでないかというのは,きっちり伝えたいので,ちょっと30%では物足りなく,50%にしたいなと思います。

デフォルト値をいじれればいいんですが,そういう設定はなさそうです。

なので,マクロで作りました。もう1年位前です。今ならもっときれいに組めるのかな。。パワーポイントのマクロが全く理解できていない時にトライアンドエラーで組んだやつです。

Sub SuperScript50All()

    Dim x As Slide
    Dim y As Shape
    Dim z As Table
    Dim zRow As Integer
    Dim zCol As Integer
    Dim rng As TextRange
    Dim i As Integer
    Dim j As Integer
    Dim k As Integer
    Dim cntHit As Integer
    
    
    cntHit = 0
    For Each x In ActivePresentation.Slides
        For Each y In x.Shapes
            If y.HasTextFrame Then
                Set rng = y.TextFrame.TextRange
                    For i = 1 To rng.Length
                        If rng.Characters(i).Font.Superscript = msoTrue Then
                            rng.Characters(i).Font.BaselineOffset = 0.5
                            cntHit = cntHit + 1
                        End If
                    Next
                    
            End If
        Next
    Next
        
    For Each x In ActivePresentation.Slides
        For Each y In x.Shapes
            If y.HasTable Then
            Set z = y.Table
            zRow = z.Rows.Count
            zCol = z.Columns.Count
            
                For j = 1 To zRow
                    For k = 1 To zCol
                        With z.Cell(j, k).Shape.TextFrame.TextRange
                            For i = 1 To .Length
                                If .Characters(i).Font.Superscript = msoTrue Then
                                    .Characters(i).Font.BaselineOffset = 0.5
                                    cntHit = cntHit + 1
                                End If
                            Next
                        End With
                    Next
                Next
            End If
        Next
    Next
    MsgBox ("上付き文字は" & cntHit & "個あり、相対位置を50%に設定しました。")
    
    
End Sub

ちゃんと見直さないといけないですね。ループ,スゴイ深さだ。。

イチオウツカエマシタヨ。。

正規表現 さらに続き

とても地味な記事が続いていますね。でもこれは乗り越える必要があるところなので,まだやってます。

前回は化学反応式を簡単な部品に分けることをやりましたので,さらにさらに分けることに取り組んでみました。

とはいえ,ムズカシイ。なんとなくパーツの意味はわかっている実感はあるんですが,うまく書けないです。

特にSubMatchesを使いこなしたいんですが,思い通りにはいきませんでした。

ただ,そのまま負けるのもくやしいので,二段階でやろうと思い,とにかくばらばらに分解することをやりました。

Sub test2()
    Dim Regex As VBScript_RegExp_55.RegExp, subRegEx As VBScript_RegExp_55.RegExp
    Set Regex = New VBScript_RegExp_55.RegExp
    Set subRegEx = New VBScript_RegExp_55.RegExp
    
    Dim ret As VBScript_RegExp_55.MatchCollection
    Dim RegMatches As VBScript_RegExp_55.MatchCollection
    Dim RegMatches2 As VBScript_RegExp_55.MatchCollection
    Dim Chem As Variant
    
    Dim strChem As String
    strChem = "Ca(OH)2+2HCl→CaCl2+2H2O"
    Dim strPattern As String
    strPattern = "[0-9A-Za-z\(\)]+|! +|→"
    
    With Regex
        .Pattern = strPattern
        .IgnoreCase = False
        .Global = True
        Set RegMatches = .Execute(strChem)
    End With
    
    Dim Result As Collection: Set Result = New Collection
    
    Dim strPattern2 As String
    strPattern2 = "([0-9]+|[A-Z][a-z]?)|\(|\)"
    
    For Each Chem In RegMatches
        With subRegEx
            .Pattern = strPattern2
            .IgnoreCase = False
            .Global = True
            Set RegMatches2 = .Execute(Chem)
        End With
        Result.Add RegMatches2
    Next
    
    Dim i As Long, j As Long
    For i = 0 To RegMatches.Count - 1
        Debug.Print RegMatches(i)
        For j = 0 To Result(i + 1).Count - 1
            Debug.Print vbTab; Result(i + 1)(j)
        Next
    Next

End Sub

実行すると,イミディエイトウィンドウに結果を吐き出します。

Ca(OH)2
    Ca
    (
    O
    H
    )
    2
2HCl
    2
    H
    Cl
→
CaCl2
    Ca
    Cl
    2
2H2O
    2
    H
    2
    O

こんな感じです。ほんとバラバラにできました。

チェックとしてこんなのも

strChem = "2NaHCO3→Na2CO3+H2O+CO2"

2NaHCO3
    2
    Na
    H
    C
    O
    3
→
Na2CO3
    Na
    2
    C
    O
    3
H2O
    H
    2
    O
CO2
    C
    O
    2

ちゃんと動いてそうですよね。

これだけのことを今回のコードの長さでできる時点ですごいなと思いますが,もっとうまく書ければたぶん,一発でSubMatchesまで含めて完全に分解できる力があると思うんですよね。

修業が足りませんね(;´▽`A``

引き続き精進します。