初投稿です
はじめに
やっぱVBAにCのsprintfほしいよね
とりあえず「VBA sprintf」とかで検索してみるとだいたいこんな結果がでてくる
Format 関数を使う
-> 変数1つしか変換できないのでダメ
System.Text.StringBuilder を使う
-> 可変個扱えるから勝ちか?と思ったが記法がまるで謎なのでクソ
自分で実装する
-> や っ ぱ こ れ だ ね
先駆者はあちこちにいるみたいだけど、ちょっと貧弱だったりそもそも使い方が違ったりなので自分で実装したいところまで実装してみような
仕様
こんな形式の関数をつくる
Public Function sprintf(fmt As String, ParamArray Prmary()) As String
実装する指定子はこちら
種類 | 説明 |
---|---|
%d | 整数 |
%f | 小数 |
%s | 文字列 |
%% | "%"という文字 |
期待される出力
Debug.Print sprintf("今日は%d月%d日、%sです",Month(Date),Day(Date),WeekdayName(Weekday(Date)))
' -> (例) 今日は4月21日、土曜日です
Debug.Print sprintf("%f %d",3.14,3.14)
' -> 3.14 3
Debug.Print sprintf("%d%%オフ",40)
' -> 40%オフ
全くいい例が思いつかなかった ごめん
んじゃ組んでみましょか
順を追ってやってくから分かりやすいと思うよ 知らんけど
実装
1. fmtを一文字ずつ走査する
まあこれが出来ないとお話にならんわな
Public Function sprintf(fmt As String, ParamArray Prmary()) As String
Dim i As Long: i = 1
Dim Result As String
Do Until i > Len(fmt)
Result = Result & Mid(fmt, i, 1)
i = i + 1
Loop
sprintf = Result
End Function
後々のことを考えてFor文ではなくUntil文を採用 柔軟に走査位置を変えたいからね
Mid(fmt, i, 1)
で、i文字目を取り出せる
私はVBAで関数を書く時はResultという変数を用意して、最後に関数名変数に代入するようにしています 多分やり方は人それぞれだろうから無理に推しはしない
2. "%"を検出する
とりあえず今は、見つけたら"!"に置換(文字"%"の代わりに"!"を追加)するようにしてみます
Public Function sprintf(fmt As String, ParamArray Prmary()) As String
Dim i As Long: i = 1
Dim Result As String
Do Until i > Len(fmt)
If Mid(fmt, i, 1) = "%" Then
Result = Result & "!"
Else
Result = Result & Mid(fmt, i, 1)
End If
i = i + 1
Loop
sprintf = Result
End Function
3. "%"の後ろの文字で処理を分岐する
走査位置を一つ後ろにずらして、dとかsとかか判定します
Select Case
を使うことで後々拡張できるようにします
Public Function sprintf(fmt As String, ParamArray Prmary()) As String
Dim i As Long: i = 1
Dim Result As String
Do Until i > Len(fmt)
If Mid(fmt, i, 1) = "%" Then
i = i + 1 '%の次の文字に進めておく
Select Case Mid(fmt, i, 1)
Case "d":
Result = Result & "<整数>"
Case "f":
Result = Result & "<小数>"
Case "s":
Result = Result & "<文字列>"
Case "%":
Result = Result & "%"
Case Else:
Debug.Print "無効な識別子" 'とりあえずこんな対応にしておく 無効な識別子は上手く無視してくれます
End Select
Else
Result = Result & Mid(fmt, i, 1)
End If
i = i + 1
Loop
sprintf = Result
End Function
このへんで少し実行例を載せてみましょうかね
Debug.Print sprintf("dd%dd")
' -> dd<整数>d
Debug.Print sprintf("%f%d%%%s")
' -> <小数><整数>%<文字列>
Debug.Print sprintf("%a%b%c%d")
' -> (複数行)
' 無効な識別子
' 無効な識別子
' 無効な識別子
' <整数>
なんかいけそうな感じしてきたでしょ?
4. 実際にPrmaryから置換
<整数>
とかってしてたとこに上手く配列を入れてあげれば良さそうですね!
検出回数をカウントする変数を新たに用意します
Public Function sprintf(fmt As String, ParamArray Prmary()) As String
Dim i As Long: i = 1
Dim j As Long: j = LBound(Prmary) 'これね
Dim Result As String
Do Until i > Len(fmt)
If Mid(fmt, i, 1) = "%" Then
i = i + 1
Select Case Mid(fmt, i, 1)
Case "d":
Result = Result & CInt(Prmary(j))
j = j + 1
Case "f":
Result = Result & CDbl(Prmary(j))
j = j + 1
Case "s":
Result = Result & CStr(Prmary(j))
j = j + 1
Case "%":
Result = Result & "%"
Case Else:
Debug.Print "無効な識別子"
End Select
Else
Result = Result & Mid(fmt, i, 1)
End If
i = i + 1
Loop
sprintf = Result
End Function
おおおおおお動いたああああああああ!!!!!!!!!
あとはお好みでフォーマット増やすなりなんなりしてみてください
以上です ありがとうございました
つづく