t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

VBA パスカル記法を単語ごとに区切って配列で返すSplitPascal関数を自作する

今回はパスカル記法を単語ごとに区切って配列で返す関数を作成する。

前回このような記事を書いたのだが、
thom.hateblo.jp

この記事を受けて@Dev_Clipsさん(サイト)からツイッター「ImageMsoの"名前"の一致率も類似画像抽出に使えそう」とのヒントを貰ったためだ。

さて、ImageMSO画像のファイル名はパスカル記法になっている。

パスカル記法とは、英単語を並べる際、単語の始まりをすべて大文字にしてスペースを入れずにくっつけた形。

例) ThisIsAPascalNotation

今回作成するのはこれを単語単位に分割し、配列に格納するための関数である。
SplitPascal関数と名付けよう。

まぁただコード書いて終わりではあんまりなので、今回は作成プロセスを追って紹介するスタイルで書く。
くどいほど少しずつ組み立ててみよう。
Functionプロシージャの組み立て方がいまひとつ難しいという方の参考になれば幸いである。

1) 枠組みを作る

Function SplitPascal()
End Function

2) 引数、戻り値を決める

今回は文字列を渡すのでString型の引数を一つだけ。

Function SplitPascal(expression As String)
End Function

戻り値は今回Variant型にするので何も書かない。

3) 戻り値を返す処理を書く

戻り値の型はVariantであるが、そこに含める中身は配列なので、配列型でret変数を作ってとりあえずそれを返す処理にする。

Function SplitPascal(expression As String)
    Dim ret()
    SplitPascal = ret
End Function

ここまでが定石。どのようなFunctionでもこの流れで作れるのでマスターしよう。
あとは戻り値であるretをどう作りこんでいくかである。

4) 1文字ずつループさせるための、枠組みを作る

1文字ずつ検査して大文字かどうかを見る必要があるので、とりあえず文字数分ループ。

Function SplitPascal(expression As String)
    Dim ret(), i
    For i = 1 To Len(expression)
        '処理
    Next
    SplitPascal = ret
End Function

5) 1文字ずつ切り出してプリントしてみる

このあと文字を切り出して、検査・加工するのだが、その前にとりあえず動作がわかるようにプリント文にしておく。

Function SplitPascal(expression As String)
    Dim ret(), i
    For i = 1 To Len(expression)
        Debug.Print Mid(expression, i, 1)
    Next
    SplitPascal = ret
End Function

6) 呼び出してみる

メインコードを書いて呼び出してみる。まだ戻り値も何も使わないけど、とりあえず1文字ずつプリントされるところまで確認。

Sub Main()
    SplitPascal "ThisIsAPascalNotation"
End Sub

7) 大文字かどうかの判定

ここで文字コードの知識が活きる。といってもコードは知らなくても大丈夫。A~Zが連番になってることを知ってれば、Asc関数とIf文で切り出した文字がA~Zの範囲に収まっているか調べられる。

Function SplitPascal(expression As String)
    Dim ret(), i
    For i = 1 To Len(expression)
        Dim char: char = Mid(expression, i, 1)
        If Asc("A") <= Asc(char) And Asc(char) <= Asc("Z") Then
            Debug.Print "★"
        End If
        Debug.Print char
    Next
    SplitPascal = ret
End Function

このとき、大文字だったら★をプリントしたのち、charを出力。大文字でなければcharだけ出力される。
イミディエイトはこんな感じ。
f:id:t-hom:20170303234345p:plain

さて、ここで閃いた。これ、一文字ずつ出力しているが、★をスペースに置き換えて一つの文字列に足していったらどうか。

8) スペース区切りで出力

retを配列ではなくてただのString型に変更し、ここに結果文字列を足しこんでいく。

Function SplitPascal(expression As String)
    Dim ret As String, i
    For i = 1 To Len(expression)
        Dim char: char = Mid(expression, i, 1)
        If Asc("A") <= Asc(char) And Asc(char) <= Asc("Z") Then
            ret = ret & " "
        End If
        ret = ret & char
    Next
    SplitPascal = ret
End Function

メインコードは戻り値を出力する形に変更。

Sub Main()
    Debug.Print SplitPascal("ThisIsAPascalNotation")
End Sub

すると、イミディエイトウインドウに「 This Is A Pascal Notation」と出力される。
このままでは先頭に1つスペースが入ってるうえ、当初の目的である配列で返すってのができていない。

9) 最後の仕上げ

まあここまで来ればあとは簡単。
余計なスペースの件はTrim関数で解決するし、配列になってない件はSplit関数で解決する。
ということで、戻り値の代入部分をちょっといじるだけ。

Function SplitPascal(expression As String)
    Dim ret As String, i
    For i = 1 To Len(expression)
        Dim char: char = Mid(expression, i, 1)
        If Asc("A") <= Asc(char) And Asc(char) <= Asc("Z") Then
            ret = ret & " "
        End If
        ret = ret & char
    Next
    SplitPascal = Split(Trim(ret))
End Function

メインコードも配列を処理するよう変更

Sub Main()
    Dim word
    For Each word In SplitPascal("ThisIsAPascalNotation")
        Debug.Print word
    Next
End Sub

出力結果はこちら

This
Is
A
Pascal
Notation

以上で完成。

ただ当初の目的であったImageMSOへの応用はあまり芳しくなく。。
なんか名前ベースで探しても毛色の違うアイコンが結構ヒットするので苦労中。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。