2020年6月8日月曜日

[VBA] 05. 文字列処理

文字列の処理についてまとめています。文字列を処理する関数や、正規表現を使った文字列の置換、抽出のサンプルも載せています。



結合
文字列を結合したい場合は & もしくは + を使う。Debug.Print や Print 文の時は ; でも可。
Debug.Print "aaa" & "bbb"
Debug.Print "ccc" + "ddd"
Debug.Print "eee"; "fff"

'改行は vbLf
Debug.Print "ggg" & vbLf & "hhh"
実行結果
aaabbb
cccddd
eeefff
ggg
hhh


分割
文字列を分割合したい場合は Split 関数を使う。連続する空白を1つに置換する記述は、後述する正規表現を使ってもOK。
Dim word1 As String, word2 As String, temp As String
Dim word_array As Variant

word1 = "aaa,bbb,ccc"
word2 = "AAA BBB    CCC"

', で分割
word_array = Split(word1, ",")

Debug.Print word_array(0)
Debug.Print word_array(1)
Debug.Print word_array(2)


'複数の空白で分割
Do Until Len(word2) = Len(temp)
    temp = word2
    word2 = Replace(word2, "  ", " ")  '2連続する空白を1つに置換
Loop
word_array = Split(word2, " ")

Debug.Print word_array(0)
Debug.Print word_array(1)
Debug.Print word_array(2)
実行結果
aaa
bbb
ccc
AAA
BBB
CCC


パターンマッチ
パターンマッチは Like 演算子を使う。(Like 演算子のワイルドカードについては演算子のページを参照。)
Dim word As String

word = "ABCDEF"

'C を含む
If word Like "*[C]*" Then
  Debug.Print "match!"
End If

'X を含まない
If word Like "*[!X]*" Then
  Debug.Print "match!"
End If
実行結果
match!
match!


抽出
文字列の抽出をする場合は Left Rigth, Mid 関数を使う。それぞれ 左端, 右端, 指定位置から指定した文字数を抽出する。

Left(string, length)
Right(string, length)
Mid(string, start, [ length ])

Dim word As String
word = "ABCDEF"

'先頭2文字を抽出
Debug.Print Left(word, 2)

'末尾2文字を抽出
Debug.Print Right(word, 2)

'3文字目から2文字を抽出
Debug.Print Mid(word, 3, 2)

'3文字目以降を抽出
Debug.Print Mid(word, 3)

'"D" より前を抽出
Debug.Print Left(word, InStr(word, "D") - 1)

'"D" より後を抽出
Debug.Print Right(word, Len(word) - InStr(word, "D"))
実行結果
AB
EF
CD
CDEF
ABC
EF

ファイルパスからファイル名や拡張子などを抽出したい場合は以下のようになる。
Dim path As String
path = "C:\aaa\bbb\sample.txt"

'ディレクトリ
Debug.Print Left(path, InStrRev(path, "\") - 1)
'ファイル名
Debug.Print Mid(path, InStrRev(path, "\") + 1)
'拡張子を除いたファイル名
Debug.Print Mid(path, InStrRev(path, "\") + 1, InStrRev(path, ".") - InStrRev(path, "\") - 1)
'拡張子
Debug.Print Mid(path, InStrRev(path, ".") + 1)
実行結果
sample.txt
sample
txt

また、FileSystemObject を使う方法もあるので一応記載しておく。実行結果は上記と同じ。
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
 
Dim path As String
path = "C:\aaa\bbb\sample.txt"
 
'ディレクトリ
Debug.Print fso.GetParentFolderName(path)
'ファイル名
Debug.Print fso.GetFileName(path)
'拡張子を除いたファイル名
Debug.Print fso.GetBaseName(path)
'拡張子
Debug.Print fso.GetExtensionName(path)
 
Set fso = Nothing


置換
文字列の置換を行う場合は Replace 関数を使う。

Replace(expression, find, replace [,start [, count [, compare ]])

 expression : 対象の文字列
 find : 検索する文字列
 replace : 置換する文字列
 start : 検索開始位置 (省略可)
 count : 置換する回数 (省略可)
 compare : 文字列比較の種類 (省略可)

compare は vbBinaryCompare (値は0) と vbTextCompare (値は1)。
start は 5 を指定した場合、1~4文字目までの文字列を削除した状態で返すので注意。

Dim tempWord As String, word1 As String, word2 As String, word3 As String

tempWord = "ABC123ABC123ABC123"

'123 を 456 に置換 (1回のみ)
word1 = Replace(tempWord, "123", "456", 1, 1)

'5文字目以降を対象に 123 を 456 に置換 (1回のみ)
word2 = Replace(tempWord, "123", "456", 5, 1)

'全ての ABC を DEF に置換
word3 = Replace(tempWord, "ABC", "DEF")

Debug.Print word1
Debug.Print word2
Debug.Print word3
実行結果
ABC456ABC123ABC123
23ABC456ABC123
DEF123DEF123DEF123


小文字/大文字に置換
英字を小文字に置換, 大文字に置換 する場合は LCase, UCase 関数を使う。

LCase ( string )
UCase ( string )

Dim word1 As String, word2 As String

word1 = "abCDef"
word2 = "abCDef"

Debug.Print LCase(word1)
Debug.Print UCase(word2)
実行結果
abcdef
ABCDEF


変換
StrConv 関数を使用して文字列の変換を行うことができる。

StrConv(string, conversion [, LCID ] )

conversion の設定は以下の通り。
 vbUpperCase 1 : 大文字に変換
 vbLowerCase 2 : 小文字に変換
 vbProperCase 3 : 各単語の先頭の文字を大文字に変換
 vbWide 4 : 全角文字に変換
 vbNarrow 8 : 半角文字に変換
 vbKatakana 16 : ひらがなをカタカナに変換
 vbHiragana 32 : カタカナをひらがなに変換
 vbUnicode 64 : Unicode に変換
 vbFromUnicode 128 : システムのコードページに変換

Dim word1 As String, word2 As String

word1 = "Guardians of the Galaxy"
word2 = "あいうえお カキクケコ"

Debug.Print StrConv(word1, vbUpperCase)
Debug.Print StrConv(word1, vbLowerCase)
Debug.Print StrConv(word1, vbProperCase)
Debug.Print StrConv(word1, vbWide)

Debug.Print StrConv(word2, vbNarrow)
Debug.Print StrConv(word2, vbKatakana)
Debug.Print StrConv(word2, vbHiragana)
実行結果
GUARDIANS OF THE GALAXY
guardians of the galaxy
Guardians Of The Galaxy
Guardians of the Galaxy
あいうえお カキクケコ
アイウエオ カキクケコ
あいうえお かきくけこ


文字数
文字列の長さを調べたい場合は Len 関数を使う。改行も1文字と認識されるので注意。
Dim word1 As String, word2 As String

word1 = "ABCDEF"
word2 = "ABC" & vbLf & "DEF"

Debug.Print Len(word1)
Debug.Print Len(word2)
実行結果
 6 
 7 


文字列の繰り返し
String 関数を使って文字列を連続させることができる。

String(number, character)
Debug.Print String(10, "-")
実行結果
----------


文字列の反転
String 関数を使って文字列の順序を連続させることができる。

StrReverse ( expression )
Dim word As String

word = "ABCDEF"

Debug.Print StrReverse(word)
実行結果
FEDCBA


位置検索
文字列の中にある指定文字列の位置を知りたい場合は InStr 関数を使う。Instr は前方から指定文字列を探索する。
後方から指定文字列を探索する場合は InStrRev 関数を使う。

InStr([start, ] string1, string2 [, compare ])

 start : 検索開始位置 (省略可)
 string1 : 対象の文字列
 string2 : 検索する文字列
 compare : 文字列比較の種類(省略可)

InStrRev(stringcheck, stringmatch, [ start, [ compare ]])

 stringcheck : 対象の文字列
 stringmatch : 検索する文字列
 start : 検索開始位置 (省略可)
 compare : 文字列比較の種類(省略可)


Dim word As String

word = "ABCDEF_ABCDEF"

'Dの位置を調べる
Debug.Print InStr(word, "D")

'5文字目以降のDの位置を調べる
Debug.Print InStr(5, word, "D")

'Dの位置を後ろから調べる
Debug.Print InStrRev(word, "D")
実行結果
 4 
 11 
 11 


余分な空白の削除
文字列の 左端, 右端, 両端 にある不要な空白を削除する場合は LTrim, RTrim, Trim 関数を使う。
ワークシート関数の TRIM では両端の空白削除に加えて文字列中の空白を1つにまとめてくれるが、VBA関数の Trim はその機能は無いので注意。(不便すぎる...)

LTrim(string)
RTrim(string)
Trim(string)

Dim tempWord As String, word1 As String, word2 As String, word3 As String

tempWord = "   ABCDEF   "  '12文字 (空白3 & 英字6 & 空白3)

Debug.Print Len(tempWord)

word1 = LTrim(tempWord)    '左端の空白を削除
word2 = RTrim(tempWord)    '右端の空白を削除
word3 = Trim(tempWord)     '両端の空白を削除

Debug.Print word1 & "|" & Len(word1)
Debug.Print word2 & "|" & Len(word2)
Debug.Print word3 & "|" & Len(word3)
実行結果
 12 
ABCDEF   |9
   ABCDEF|9
ABCDEF|6


比較
文字列を比較する StrComp 関数もある。

StrComp(string1, string2 [, compare ])

戻り値は以下のようになっている。
 string1 が string2 より小さい : -1
 string1 と string2 が等しい : 0
 string1 が string2 より大きい : 1
 string1 または string2 が Null である : Null

Dim word1 As String, word2 As String, word3 As String

word1 = "ABC"
word2 = "abc"
word3 = "ABZ"

Debug.Print StrComp(word1, word2)
Debug.Print StrComp(word1, word1)
Debug.Print StrComp(word2, word3)
実行結果
-1 
 0 
 1 


書式の指定
書式を指定したい場合に使用する。

Format(expression [, format ] [, firstdayofweek ] [, firstweekofyear ])

 expression : 文字列
 format : 書式 (省略可能)
 firstdayofweek : 週の始まりの曜日を表す定数 (省略可能)
 firstweekofyear : 年の第 1 週を指定する定数 (省略可能)

例えば、日付であれば 〇年〇月〇日 や 〇/〇/〇 の形式などを指定できるらしい。あまり使い道がなさそうと思い詳細は調べていないが、事務的な仕事の人は使うのかも。
以下の2つは使えそう。
Dim word As String

word = "1234567"

Debug.Print Format(word, "#,#")        '区切り挿入
Debug.Print Format(word, "00000000")   '8桁表示 (不足は0埋めされる)
実行結果
1,234,567
01234567

16進数を扱う場合 "0000_0000" とすると見やすいが、HEX2DEC 等が使えなくなるのが難点。


正規表現
正規表現を使いたい場合は RegExp オブジェクトの参照を有効にする必要がある。

1. メニューバーのツール → 参照設定 を選択
2. Microsoft VBScript Regular Expressions 5.5 にチェックを入れる

正規表現の使い方は色々あると思うが、2つほどサンプルを記載する。

1. 連続する数字を , に置換する。Replace 関数の置換ではで手に負えないときに使う。
'正規表現オブジェクト (RegExp)
Dim reg As Object
Set reg = CreateObject("VBScript.RegExp")

With reg
    .Pattern = "[0-9]+"  'パターンを指定
    .IgnoreCase = False  '大文字と小文字を区別する (True/False)
    .Global = True       '文字列全体を検索 (True/False)
End With

'置換
Dim tempWord As String, word As String

tempWord = "ABC123ABC456ABC789"

word = reg.Replace(tempWord, ",")

Debug.Print word
実行結果
ABC,ABC,ABC,


2. 括弧内の文字列を抽出する。
'正規表現オブジェクト (RegExp)
Dim reg As Object
Set reg = CreateObject("VBScript.RegExp")

With reg
    .Pattern = "\(.*?\)"  'パターンを指定
    .IgnoreCase = False   '大文字と小文字を区別 (True/False)
    .Global = True        '文字列全体を検索 (True/False)
End With

'抽出
Dim tempWord As String, word1 As String, word2 As String
Dim regWord As Variant

tempWord = "ABC(123)DEF(456)GHI"

Set regWord = reg.Execute(tempWord)

Debug.Print regWord(0).Value
Debug.Print regWord(1).Value

'括弧を削除
word1 = Replace(Replace(regWord(0).Value, "(", ""), ")", "")
word2 = Replace(Replace(regWord(1).Value, "(", ""), ")", "")

Debug.Print word1
Debug.Print word2
実行結果
(123)
(456)
123
456

括弧がついてくるのが予想外だったが、うまい書き方が思いつかず。。。
パターンの ? は最短一致であることを示す。? が無い場合は (123)DEF(456) が抽出される。


0 件のコメント:

コメントを投稿