Accessのレポートオブジェクトのコントロール値などのオブジェクトの文字を他の文字に置き換えるとき、改行文字が含まれていて置換できないって経験があるのではないでしょうか?
私自身がその経験があり、改行文字を考慮した置換を紹介しているサイトが無かったので記事にしました。
当記事のサンプルコードにある関数をコピペするだけで使用できるので皆さんもよかったら使ってみてください。
サンプルコードは、私自身が作成したオリジナルのプログラムです。
分かりやすくするために必要最低限のプログラムのみ書いています。
また、Dimの宣言は必要ないといった皆さん自身のルールがあるかもしれませんがご理解ください。
当記事は、実践編としてVBScriptの基本的な文法がわかる中級者の方にご紹介しています。
基本的な文法がわからない方は、初級編の記事も紹介しているのでそちらを参考にしてください。
特定の文字を含むとき、指定した文字を置換するサンプルコード
SampleCode.vbs
'【関数】文字の置換(改行を考慮)
Function CusReplace(ByVal target,ByVal mae,ByVal ato)
'改行コード無しの置換対象の文字
Dim targetNotCrLf : targetNotCrLf = Replace(Replace(target,vbCr,""),vbLf,"")
'置換対象の文字に置換前の文字が存在するか?
If Instr(targetNotCrLf,mae) <= 0 Then CusReplace = target : Exit Function Else
'置換対象の文字を置換
CusReplace = Replace(targetNotCrLf,mae,ato)
'置換対象の文字に改行コードが何個あるか
Dim cntCr : cntCr = UBound(Split(target, vbCr))
Dim cntLf : cntLf = UBound(Split(target, vbLf))
'含まれる改行コードの位置を保持する配列
Dim objPosCrLf : Set objPosCrLf = CreateObject("System.Collections.ArrayList")
'Crの位置を取得する処理
If cntCr > 0 Then
'Cr数分ループ
Dim posCr : posCr = 0
For i = 1 To cntCr
'x個目の改行コードが存在しない場合ループから抜ける
If InStr(posCr + 1, target, vbCr) <= 0 Then Exit For Else
'位置を取得
posCr = InStr(posCr + 1, target, vbCr)
'位置を保持
objPosCrLf.Add Right("000" & posCr, 3) & "_Cr"
Next
Else
End If
'Lfの位置を取得する処理
If cntLf > 0 Then
'Lf数分ループ
Dim posLf : posLf = 0
For i = 1 To cntLf
'x個目の改行コードが存在しない場合ループから抜ける
If InStr(posLf + 1, target, vbLf) <= 0 Then Exit For Else
'位置を取得
posLf = InStr(posLf + 1, target, vbLf)
'位置を保持
objPosCrLf.Add Right("000" & posLf, 3) & "_Lf"
Next
Else
End If
'改行位置のソート
objPosCrLf.Sort
'改行の挿入
For Each index In objPosCrLf
'位置と改行コードに分ける
aryTmp = Split(index,"_")
'RegExpオブジェクトを作成
Set objReg = New RegExp
'パターンの設定
objReg.Pattern = "([0]*(?=[1-9]))(\d+)"
'頭0を削除した位置のパターンを取得
Dim posNum : posNum = objReg.Replace(aryTmp(0),"$2")
'StringBuilderオブジェクト作成
Dim sb : Set sb = CreateObject("System.Text.StringBuilder")
'文字の追加
sb.Append_3 CusReplace
'改行コードの挿入
Select Case aryTmp(1)
Case "Cr"
sb.Insert_2 posNum - 1,vbCr
Case "Lf"
sb.Insert_2 posNum - 1,vbLf
Case Else
End Select
'更新
CusReplace = sb.ToString()
'後始末
Set sb = Nothing
Next
'後始末
Set objPosCrLf = Nothing
End Function
'【結果】→ "置" & vbLf & "換" & vbCrLf & "後"
Msgbox CusReplace("置" & vbLf & "換" & vbCrLf & "前","置換前","置換後")
解説①:引数について
1つ目の引数「target」は、改行を含んだ置換したい対象の文字を渡してください。
改行コード「Cr」「Lf」「CrLf」のどれが含まれていても大丈夫です。
また、複数個の改行コードにも対応しています。
2つ目の引数「mae」は、置換したい文字を渡してください。
3つ目の引数「ato」は、置換後の文字を渡してください。
解説②:置換したい文字を含むかチェック
はじめに、引数1に引数2の置換したい文字が含まれているかをチェックしています。
そもそも含まれていなければ、処理を続ける必要がありません。
引数1をそのまま返し、Exit Functionで関数を抜けています。
エラーチェックが必要な方は、関数を抜けた後の処理でチェックを行ってください。
解説③:含まれている改行コードの個数を取得
改行コード(Cr)の個数を「Dim cntCr : cntCr = UBound(Split(target, vbCr))」で取得しています。
改行コード(Lf)の個数を「Dim cntLf : cntLf = UBound(Split(target, vbLf))」で取得しています。
引数1をSplit関数を使って改行コードで分割し、配列化します。
UBound関数で配列の要素数を取得することで改行コードの個数を取得しています。
解説④:含まれている改行コードの位置を取得
InStr関数をループさせ、引数1の左から順番に見つけた改行コードの位置をListクラスのオブジェクトに格納しています。
格納するときに、「頭3桁で0埋めした位置の番号」と「どの改行コードかを表す文字」を結合させて格納しています。
「頭3桁で0埋めした位置の番号」の3桁は、置換したい文字に999個以内の改行コードを含んでいることを意味します。
2桁の99個以内でも良いかなと思いましたが、念のため3桁にしています。
改行コード「Cr」「Lf」は、それぞれ処理を分けて位置を取得しています。
解説⑤:改行位置のソート
Listクラスのオブジェクトに格納した値を「objPosCrLf.Sort」でソートしています。
例えば、List内の値が「004,002,005」の場合、ソートすると「002,004,005」になります。
この処理を行う理由を説明する前にサンプルコードの処理の流れを簡単に説明します。
① 改行コードを削除した文字に置換したい文字が含まれるかチェック
↓
② 改行を削除した文字を置換する
↓
③ 改行コードの位置を取得する
↓
④ 置換後の文字②に改行コードを挿入する
置換後の文字に改行コードを挿入していくので、左から順番に挿入しないと、文字位置がずれてしまいます。
そのため、昇順でソートします。
解説⑥:改行コードの挿入
後は、置換後の文字に改行コードを挿入するだけです。
正規表現を使って0埋めされた値「002」などを先頭0を除いた「2」の挿入位置の数値を取得しています。
StringBuilderオブジェクトのInsertメソッドを使用して改行コードを挿入しています。