【VBA】文字化け地獄を完全解決!BOM有無・UTF-8/Shift-JISを自動判別して安全にCSVを読み込む「文字コード自動判定関数」
VBAの標準機能に「文字コードを自動判別する」スイッチはありませんが、ファイルをバイナリ(生のバイト列)として読み込み、「BOMの有無」や「UTF-8特有のバイト並びルール」を判定する自作関数を作成すれば自動判別可能です。
以下のコードをモジュールに貼り付けることで、UTF-8(BOMあり/なし)かShift-JISかを判定し、適切な文字コードでファイルを読み込めるようになります。
1. 文字コード自動判別関数
Option Explicit
' ファイルの文字コード(UTF-8 または Shift-JIS)を判定する関数
Public Function DetectEncoding(ByVal filePath As String) As String
Dim fileNum As Integer
Dim bytes() As Byte
Dim fileLen As Long
fileNum = FreeFile
Open filePath For Binary Access Read As #fileNum
fileLen = LOF(fileNum)
If fileLen = 0 Then
Close #fileNum
DetectEncoding = "Shift-JIS"
Exit Function
End If
' 先頭から最大4096バイトを取得して判定
Dim readLen As Long
readLen = IIf(fileLen > 4096, 4096, fileLen)
ReDim bytes(0 To readLen - 1)
Get #fileNum, 1, bytes
Close #fileNum
' 1. UTF-8 BOMの判定 (EF BB BF)
If readLen >= 3 Then
If bytes(0) = &HEF And bytes(1) = &HBB And bytes(2) = &HBF Then
DetectEncoding = "UTF-8"
Exit Function
End If
End If
' 2. BOMなしUTF-8のバイト構造チェック
Dim i As Long
Dim isUtf8 As Boolean
Dim hasMultiByte As Boolean
isUtf8 = True
i = 0
Do While i < readLen
Dim b As Byte
b = bytes(i)
If b < &H80 Then
' 1バイト文字 (ASCII)
i = i + 1
ElseIf (b And &HE0) = &HC0 Then
' UTF-8 2バイト文字
If i + 1 >= readLen Or (bytes(i + 1) And &HC0) <> &H80 Then isUtf8 = False: Exit Do
hasMultiByte = True
i = i + 2
ElseIf (b And &HF0) = &HE0 Then
' UTF-8 3バイト文字(日本語の多くはここ)
If i + 2 >= readLen Or (bytes(i + 1) And &HC0) <> &H80 Or (bytes(i + 2) And &HC0) <> &H80 Then isUtf8 = False: Exit Do
hasMultiByte = True
i = i + 3
ElseIf (b And &HF8) = &HF0 Then
' UTF-8 4バイト文字(絵文字など)
If i + 3 >= readLen Or (bytes(i + 1) And &HC0) <> &H80 Or (bytes(i + 2) And &HC0) <> &H80 Or (bytes(i + 3) And &HC0) <> &H80 Then isUtf8 = False: Exit Do
hasMultiByte = True
i = i + 4
Else
' UTF-8のルールに違反(=Shift-JISの可能性が高い)
isUtf8 = False
Exit Do
End If
Loop
If isUtf8 And hasMultiByte Then
DetectEncoding = "UTF-8"
Else
DetectEncoding = "Shift-JIS"
End If
End Function
' ファイルの文字コード(UTF-8 または Shift-JIS)を判定する関数
Public Function DetectEncoding(ByVal filePath As String) As String
Dim fileNum As Integer
Dim bytes() As Byte
Dim fileLen As Long
fileNum = FreeFile
Open filePath For Binary Access Read As #fileNum
fileLen = LOF(fileNum)
If fileLen = 0 Then
Close #fileNum
DetectEncoding = "Shift-JIS"
Exit Function
End If
' 先頭から最大4096バイトを取得して判定
Dim readLen As Long
readLen = IIf(fileLen > 4096, 4096, fileLen)
ReDim bytes(0 To readLen - 1)
Get #fileNum, 1, bytes
Close #fileNum
' 1. UTF-8 BOMの判定 (EF BB BF)
If readLen >= 3 Then
If bytes(0) = &HEF And bytes(1) = &HBB And bytes(2) = &HBF Then
DetectEncoding = "UTF-8"
Exit Function
End If
End If
' 2. BOMなしUTF-8のバイト構造チェック
Dim i As Long
Dim isUtf8 As Boolean
Dim hasMultiByte As Boolean
isUtf8 = True
i = 0
Do While i < readLen
Dim b As Byte
b = bytes(i)
If b < &H80 Then
' 1バイト文字 (ASCII)
i = i + 1
ElseIf (b And &HE0) = &HC0 Then
' UTF-8 2バイト文字
If i + 1 >= readLen Or (bytes(i + 1) And &HC0) <> &H80 Then isUtf8 = False: Exit Do
hasMultiByte = True
i = i + 2
ElseIf (b And &HF0) = &HE0 Then
' UTF-8 3バイト文字(日本語の多くはここ)
If i + 2 >= readLen Or (bytes(i + 1) And &HC0) <> &H80 Or (bytes(i + 2) And &HC0) <> &H80 Then isUtf8 = False: Exit Do
hasMultiByte = True
i = i + 3
ElseIf (b And &HF8) = &HF0 Then
' UTF-8 4バイト文字(絵文字など)
If i + 3 >= readLen Or (bytes(i + 1) And &HC0) <> &H80 Or (bytes(i + 2) And &HC0) <> &H80 Or (bytes(i + 3) And &HC0) <> &H80 Then isUtf8 = False: Exit Do
hasMultiByte = True
i = i + 4
Else
' UTF-8のルールに違反(=Shift-JISの可能性が高い)
isUtf8 = False
Exit Do
End If
Loop
If isUtf8 And hasMultiByte Then
DetectEncoding = "UTF-8"
Else
DetectEncoding = "Shift-JIS"
End If
End Function
2. 自動判別してCSVを読み込む実装例
判別した文字コードを ADODB.Stream に渡すことで、文字化けを防いで読み込めます。
Public Sub ReadCSVWithAutoDetect(ByVal filePath As String)
Dim charSet As String
' 文字コードを自動判別
charSet = DetectEncoding(filePath)
Dim stream As Object
Set stream = CreateObject("ADODB.Stream")
stream.Type = 2 ' adTypeText
stream.Charset = charSet
stream.Open
stream.LoadFromFile filePath
' 全文読み込み
Dim content As String
content = stream.ReadText(-1)
stream.Close
MsgBox "判定結果: " & charSet & vbCrLf & vbCrLf & "先頭100文字:" & vbCrLf & Left(content, 100)
End Sub
Dim charSet As String
' 文字コードを自動判別
charSet = DetectEncoding(filePath)
Dim stream As Object
Set stream = CreateObject("ADODB.Stream")
stream.Type = 2 ' adTypeText
stream.Charset = charSet
stream.Open
stream.LoadFromFile filePath
' 全文読み込み
Dim content As String
content = stream.ReadText(-1)
stream.Close
MsgBox "判定結果: " & charSet & vbCrLf & vbCrLf & "先頭100文字:" & vbCrLf & Left(content, 100)
End Sub
PR