VBAでCSVファイルなどのファイル読み込みをする際に、そのファイルの文字コードが不明な場合でも、文字コード判別して読み込めるようにしたいと思いました。
外部システムから連携されてくるデータなどは文字コードが決まっているので問題ないケースが多いですが、ユーザが作ったファイルはどの文字コードで登録されているかわからないためです。
(多くの場合は、SJISかUTF-8のどちらかだと思いますが。)
そこで、主要な文字コードを判別してファイル読み込みを行う方法を調べました。
前置き:完璧に文字コードを判別する方法はない
前提として、完璧に文字コードを判別する方法はないと思われます。
超天才たちが開発しているブラウザですら、文字コードを誤って文字化けを起こすことがありますからね。
なぜなら文字コードを表すようなメタ情報は存在しないため、ビット列を見て推測をするしか無いからです。
UTF-8にはBOMというUTF-8であることを表す文字を先頭につけることがありますが、BOMがついていないのにUTF-8というパターンもあります。
そのため、どんな判別方法でも特殊なパターンの場合はうまく行かないようになっていると思います。
まあファイルをすべて読み込んで、全量データから判断すれば完璧にコード判別できるかもですが、そこまで頑張る気になっているコードは他の言語も含めてみたことがないですね。
ADODB.Streamの自動判定は使えない
VBAのファイル読み込みでよく利用するADODB.Streamには、文字コードを自動で判定してくれるオプションがあるので、これを利用すれば良さそうと思いました。
しかし、結論から言うと使い物になりませんでした。
Charsetに_autodetect_allを指定すると、自動で判別してくれるモードになるのですが、
UTF-8のテキストファイルを読み込んだら普通に文字化けした…。
BOMをつけても駄目なので判定は相当ゴミだと思います。
文字コード判別のアルゴリズムを自力で調べて、自作する気力はないので半ば諦めていました。
文字コード判別用関数を作成している神がいた
しかし、世の中にはすごい人がいるもので、自作で文字コードを判別するVB6のプログラムを作成されている方がいました。
http://nonsoft.la.coocan.jp/SoftSample/SampleModJUDG.html
VB6のコードはVBAにも流用することができるので、ロジックを流用させていただくことにしました。
文字コード判別の関数の戻り値だけは、ADODB.Streamで使用できる定数名に変更をさせていただきました。
またファイル読み込みの部分であるgetLines関数は、自分のオリジナルになります。
ファイルパスを引数で渡すと、改行区切りでsplitした文字列の配列を返却してくれます。(CRLF、LFの両方に対応しています。)
コードの後に簡単な説明を記載しています。
'****************************************************************************
'JudgeCodeの戻り値だけ改変させてもらってします
'その他のコードは下記を参照させていただきました。
'http://nonsoft.la.coocan.jp/SoftSample/SampleModJUDG.html
'****************************************************************************
'****************************************************************************
' 機能名 : Module1.bas
' 機能説明 : 文字コード判定
' 備考 :
' 著作権 : Copyright(C) 2008 - 2009 のん All rights reserved
' ---------------------------------------------------------------------------
' 使用条件 : このサイトの内容を使用(流用/改変/転載/等全て)した成果物を不特定
' : 多数に公開/配布する場合は、このサイトを参考にした旨を記述してく
' : ださい。(例)WEBページやReadMeにリンクを貼ってください
' ---------------------------------------------------------------------------
'****************************************************************************
Private Const JUDGEFIX = 9999 '文字コード決定%
Private Const JUDGEFIX_BOM = 999999
Private Const JUDGESIZEMAX = 1000 '文字コード判定バイト数
Private Const SingleByteWeight = 1 '1バイト 文字コードの一致重み
Private Const Multi_ByteWeight = 2 '複数バイト文字コードの一致重み
Private Enum JISMODE 'JISコードのモード
ctrl = 0 '制御コード
asci = 1 'ASCII
roma = 2 'JISローマ字
kana = 3 'JISカナ(半角カナ)
kanO = 4 '旧JIS漢字 (1978)
kanN = 5 '新JIS漢字 (1983/1990)
kanH = 6 'JIS補助漢字
End Enum
'----文字コード判定
' 関数名 : JudgeCode
' 返り値 : 判定結果文字コード名
' 引き数 : bytCode : 判定文字データ
' 機能説明 : 文字コードを判定する
' 備考 :
Public Function JudgeCode(ByRef bytCode() As Byte) As String
JudgeCode = "Shift_JIS"
Dim lngSJIS As Long
Dim lngJIS As Long
Dim lngEUC As Long
Dim lngUNI As Long
Dim lngUTF7 As Long
Dim lngUTF8 As Long
lngJIS = JudgeJIS(bytCode, True)
If lngJIS >= JUDGEFIX Then JudgeCode = "JIS": Exit Function
lngUNI = JudgeUNI(bytCode, True)
If lngUNI >= JUDGEFIX Then JudgeCode = "Unicode": Exit Function
lngUTF8 = JudgeUTF8(bytCode, True)
If lngUTF8 >= JUDGEFIX Then JudgeCode = "UTF-8": Exit Function
lngUTF7 = JudgeUTF7(bytCode, True)
If lngUTF7 >= JUDGEFIX Then JudgeCode = "UTF-7": Exit Function
lngSJIS = JudgeSJIS(bytCode, True)
If lngSJIS >= JUDGEFIX Then JudgeCode = "Shift_JIS": Exit Function
lngEUC = JudgeEUC(bytCode, True)
If lngEUC >= JUDGEFIX Then JudgeCode = "euc-jp": Exit Function
If lngSJIS >= lngSJIS And lngSJIS >= lngUNI And lngSJIS >= lngJIS And _
lngSJIS >= lngUTF7 And lngSJIS >= lngUTF8 And lngSJIS >= lngEUC Then
JudgeCode = "Shift_JIS"
Exit Function
End If
If lngUNI >= lngSJIS And lngUNI >= lngUNI And lngUNI >= lngJIS And _
lngUNI >= lngUTF7 And lngUNI >= lngUTF8 And lngUNI >= lngEUC Then
JudgeCode = "Unicode"
Exit Function
End If
If lngJIS >= lngSJIS And lngJIS >= lngUNI And lngJIS >= lngJIS And _
lngJIS >= lngUTF7 And lngJIS >= lngUTF8 And lngJIS >= lngEUC Then
JudgeCode = "JIS"
Exit Function
End If
If lngUTF7 >= lngSJIS And lngUTF7 >= lngUNI And lngUTF7 >= lngJIS And _
lngUTF7 >= lngUTF7 And lngUTF7 >= lngUTF8 And lngUTF7 >= lngEUC Then
JudgeCode = "UTF-7"
Exit Function
End If
If lngUTF8 >= lngSJIS And lngUTF8 >= lngUNI And lngUTF8 >= lngJIS And _
lngUTF8 >= lngUTF7 And lngUTF8 >= lngUTF8 And lngUTF8 >= lngEUC Then
JudgeCode = "UTF-8"
Exit Function
End If
If lngEUC >= lngSJIS And lngEUC >= lngUNI And lngEUC >= lngJIS And _
lngEUC >= lngUTF7 And lngEUC >= lngUTF8 And lngEUC >= lngEUC Then
JudgeCode = "euc-jp"
Exit Function
End If
End Function
'----SJIS関係
' 関数名 : JudgeSJIS
' 返り値 : 判定結果確率(%)
' 引き数 : bytCode : 判定文字データ
' : fixFlag : 確定判断有無
' 機能説明 : SJISの文字コード判定(可能性)確率を計算する
' 備考 :
Private Function JudgeSJIS(ByRef bytCode() As Byte, _
Optional fixFlag As Boolean = False) As Integer
Dim i As Long
Dim lngFit As Long
Dim lngUB As Long
lngUB = JUDGESIZEMAX - 1
If lngUB > UBound(bytCode()) Then
lngUB = UBound(bytCode())
End If
For i = 0 To lngUB
'81-9F,E0-EF(1バイト目)
If (bytCode(i) >= &H81 And bytCode(i) <= &H9F) Or _
(bytCode(i) >= &HE0 And bytCode(i) <= &HEF) Then
If i <= UBound(bytCode) - 1 Then
'40-7E,80-FC(2バイト目)
If (bytCode(i + 1) >= &H40 And bytCode(i + 1) <= &H7E) Or _
(bytCode(i + 1) >= &H80 And bytCode(i + 1) <= &HFC) Then
lngFit = lngFit + (2 * Multi_ByteWeight)
i = i + 1
End If
End If
'A1-DF(1バイト目)
ElseIf (bytCode(i) >= &HA1 And bytCode(i) <= &HDF) Then
lngFit = lngFit + (1 * SingleByteWeight)
'20-7E(1バイト目)
ElseIf (bytCode(i) >= &H20 And bytCode(i) <= &H7E) Then
lngFit = lngFit + (1 * SingleByteWeight)
'00-1F, 7F(1バイト目)
ElseIf (bytCode(i) >= &H0 And bytCode(i) <= &H1F) Or _
bytCode(i) = &H7F Then
lngFit = lngFit + (1 * SingleByteWeight)
End If
Next i
JudgeSJIS = (lngFit * 100) / ((lngUB + 1) * Multi_ByteWeight)
End Function
'----JIS関係
' 関数名 : JudgeJIS
' 返り値 : 判定結果確率(%)
' 引き数 : bytCode : 判定文字データ
' : fixFlag : 確定判断有無
' 機能説明 : JISの文字コード判定(可能性)確率を計算する
' 備考 :
Private Function JudgeJIS(ByRef bytCode() As Byte, _
Optional fixFlag As Boolean = False) As Integer
Dim i As Long
Dim lngFit As Long
Dim lngMode As JISMODE
Dim lngUB As Long
lngUB = JUDGESIZEMAX - 1
If lngUB > UBound(bytCode()) Then
lngUB = UBound(bytCode())
End If
For i = 0 To lngUB
'1B(1バイト目)
If bytCode(i) = &H1B Then
If i <= UBound(bytCode) - 2 Then
'28 42(2・3バイト目)
If bytCode(i + 1) = &H28 And bytCode(i + 1) <= &H42 Then
lngMode = asci
lngFit = lngFit + (3 * Multi_ByteWeight)
i = i + 2
If fixFlag Then
JudgeJIS = JUDGEFIX
Exit Function
End If
End If
'28 4A(2・3バイト目)
If bytCode(i + 1) = &H28 And bytCode(i + 1) <= &H4A Then
lngMode = roma
lngFit = lngFit + (3 * Multi_ByteWeight)
i = i + 2
If fixFlag Then
JudgeJIS = JUDGEFIX
Exit Function
End If
End If
'28 49(2・3バイト目)
If bytCode(i + 1) = &H28 And bytCode(i + 1) <= &H49 Then
lngMode = kana
lngFit = lngFit + (3 * Multi_ByteWeight)
i = i + 2
If fixFlag Then
JudgeJIS = JUDGEFIX
Exit Function
End If
End If
'24 40(2・3バイト目)
If bytCode(i + 1) = &H24 And bytCode(i + 1) <= &H40 Then
lngMode = kanO
lngFit = lngFit + (3 * Multi_ByteWeight)
i = i + 2
If fixFlag Then
JudgeJIS = JUDGEFIX
Exit Function
End If
End If
'24 42(2・3バイト目)
If bytCode(i + 1) = &H24 And bytCode(i + 1) <= &H42 Then
lngMode = kanN
lngFit = lngFit + (3 * Multi_ByteWeight)
i = i + 2
If fixFlag Then
JudgeJIS = JUDGEFIX
Exit Function
End If
End If
'24 44(2・3バイト目)
If bytCode(i + 1) = &H24 And bytCode(i + 1) <= &H44 Then
lngMode = kanH
lngFit = lngFit + (3 * Multi_ByteWeight)
i = i + 2
If fixFlag Then
JudgeJIS = JUDGEFIX
Exit Function
End If
End If
End If
Else
Select Case lngMode
Case ctrl, asci, roma
'00-1F,7F
If (bytCode(i) >= &H0 And bytCode(i) <= &H1F) Or _
bytCode(i) = &H7F Then
lngFit = lngFit + (1 * SingleByteWeight)
End If
'20-7E
If (bytCode(i) >= &H20 And bytCode(i) <= &H7E) Then
lngFit = lngFit + (1 * SingleByteWeight)
End If
Case kana
'21-5F
If (bytCode(i) >= &H21 And bytCode(i) <= &H5F) Then
lngFit = lngFit + (1 * SingleByteWeight)
End If
Case kanO, kanN, kanH
If i <= UBound(bytCode) - 1 Then
'21-7E
If (bytCode(i) >= &H21 And bytCode(i) <= &H7E) And _
(bytCode(i - 1) >= &H21 And bytCode(i - 1) <= &H7E) Then
lngFit = lngFit + (2 * Multi_ByteWeight)
i = i + 1
End If
End If
End Select
End If
Next i
JudgeJIS = (lngFit * 100) / ((lngUB + 1) * Multi_ByteWeight)
End Function
'----EUC関係
' 関数名 : JudgeEUC
' 返り値 : 判定結果確率(%)
' 引き数 : bytCode : 判定文字データ
' : fixFlag : 確定判断有無
' 機能説明 : EUCの文字コード判定(可能性)確率を計算する
' 備考 :
Private Function JudgeEUC(ByRef bytCode() As Byte, _
Optional fixFlag As Boolean = False) As Integer
Dim i As Long
Dim lngFit As Long
Dim lngUB As Long
lngUB = JUDGESIZEMAX - 1
If lngUB > UBound(bytCode()) Then
lngUB = UBound(bytCode())
End If
For i = 0 To lngUB
'8E(1バイト目) + A1-DF(2バイト目)
If bytCode(i) = &H8E Then
If i <= UBound(bytCode) - 1 Then
If bytCode(i + 1) >= &HA1 And bytCode(i + 1) <= &HDF Then
lngFit = lngFit + (2 * Multi_ByteWeight)
i = i + 1
End If
End If
'8F(1バイト目) + A1-0xFE(2・3バイト目)
ElseIf bytCode(i) = &H8F Then
If i <= UBound(bytCode) - 2 Then
If (bytCode(i + 1) >= &HA1 And bytCode(i + 1) <= &HFE) And _
(bytCode(i + 2) >= &HA1 And bytCode(i + 2) <= &HFE) Then
lngFit = lngFit + (3 * Multi_ByteWeight)
i = i + 2
End If
End If
'A1-FE(1バイト目) + A1-FE(2バイト目)
ElseIf bytCode(i) >= &HA1 And bytCode(i) <= &HFE Then
If i <= UBound(bytCode) - 1 Then
If bytCode(i + 1) >= &HA1 And bytCode(i + 1) <= &HFE Then
lngFit = lngFit + (2 * Multi_ByteWeight)
i = i + 1
End If
End If
'20-7E(1バイト目)
ElseIf (bytCode(i) >= &H20 And bytCode(i) <= &H7E) Then
lngFit = lngFit + (1 * SingleByteWeight)
'00-1F, 7F(1バイト目)
ElseIf (bytCode(i) >= &H0 And bytCode(i) <= &H1F) Or _
bytCode(i) = &H7F Then
lngFit = lngFit + (1 * SingleByteWeight)
End If
Next i
JudgeEUC = (lngFit * 100) / ((lngUB + 1) * Multi_ByteWeight)
End Function
'----UNICODE関係
' 関数名 : JudgeUNI
' 返り値 : 判定結果確率(%)
' 引き数 : bytCode : 判定文字データ
' : fixFlag : 確定判断有無
' 機能説明 : UTF16の文字コード判定(可能性)確率を計算する
' 備考 :
Private Function JudgeUNI(ByRef bytCode() As Byte, _
Optional fixFlag As Boolean = False) As Integer
Dim i As Long
Dim lngFit As Long
Dim lngUB As Long
lngUB = JUDGESIZEMAX - 1
If lngUB > UBound(bytCode()) Then
lngUB = UBound(bytCode())
End If
For i = 0 To lngUB
If fixFlag Then
'BOM
If bytCode(i) = &HFF Then
If i <= UBound(bytCode) - 1 Then
If bytCode(i + 1) = &HFE Then
JudgeUNI = JUDGEFIX
Exit Function
End If
End If
End If
'半角の証
'If bytCode(i) = &H0 Then
' JudgeUNI = JUDGEFIX
' Exit Function
'End If
End If
If i <= UBound(bytCode) - 1 Then
'00(2バイト目)
If (bytCode(i + 1) = &H0) Then
'00-FF(1バイト目)
lngFit = lngFit + (2 * Multi_ByteWeight)
'01-33(2バイト目)
ElseIf (bytCode(i + 1) >= &H1 And bytCode(i + 1) <= &H33) Then
'00-FF(1バイト目)
lngFit = lngFit + (2 * Multi_ByteWeight)
'34-4D(2バイト目)
ElseIf (bytCode(i + 1) >= &H34 And bytCode(i + 1) <= &H4D) Then
'00-FF(1バイト目)----空き----
lngFit = 0
Exit For
'4E-9F(2バイト目)
ElseIf (bytCode(i + 1) >= &H4E And bytCode(i + 1) <= &H9F) Then
'00-FF(1バイト目)
lngFit = lngFit + (2 * Multi_ByteWeight)
'A0-AB(2バイト目)
ElseIf (bytCode(i + 1) >= &HA0 And bytCode(i + 1) <= &HAB) Then
'00-FF(1バイト目)----空き----
lngFit = 0
Exit For
'AC-D7(2バイト目)
ElseIf (bytCode(i + 1) >= &HAC And bytCode(i + 1) <= &HD7) Then
'00-FF(1バイト目)----ハングル----
lngFit = 0
Exit For
'D8-DF(2バイト目)
ElseIf (bytCode(i + 1) >= &HD8 And bytCode(i + 1) <= &HDF) Then
'00-FF(1バイト目)
lngFit = lngFit + (2 * Multi_ByteWeight)
'E0-F7(2バイト目)
ElseIf (bytCode(i + 1) >= &HE0 And bytCode(i + 1) <= &HF7) Then
'00-FF(1バイト目)----外字----
lngFit = 0
Exit For
'F8-FF(2バイト目)
ElseIf (bytCode(i + 1) >= &HF8 And bytCode(i + 1) <= &HFF) Then
'00-FF(1バイト目)
lngFit = lngFit + (2 * Multi_ByteWeight)
End If
i = i + 1
End If
Next i
JudgeUNI = (lngFit * 100) / ((lngUB + 1) * Multi_ByteWeight)
End Function
'----UTF7関係
' 関数名 : JudgeUTF7
' 返り値 : 判定結果確率(%)
' 引き数 : bytCode : 判定文字データ
' : fixFlag : 確定判断有無
' 機能説明 : UTF7の文字コード判定(可能性)確率を計算する
' 備考 :
Private Function JudgeUTF7(ByRef bytCode() As Byte, _
Optional fixFlag As Boolean = False) As Integer
Dim i As Long
Dim lngFit As Long
Dim lngWrk As Long
Dim str64 As String
Dim bln64 As Boolean
str64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
Dim lngUB As Long
Dim lngBY As Long
Dim lngXB As Long
Dim lngXX As Long
lngUB = JUDGESIZEMAX - 1
If lngUB > UBound(bytCode()) Then
lngUB = UBound(bytCode())
End If
lngWrk = 0
For i = 0 To lngUB
'+~-まではBASE64ENCODE
If bytCode(i) = Asc("+") And bln64 = False Then
lngWrk = 1
bln64 = True
ElseIf bytCode(i) = Asc("-") Then
If lngWrk <= 0 Then
lngWrk = lngWrk + 1
lngFit = lngFit + (lngWrk * SingleByteWeight)
ElseIf lngWrk = 1 Then
lngWrk = lngWrk + 1
lngFit = lngFit + (lngWrk * Multi_ByteWeight)
ElseIf lngWrk >= 4 And lngXB < 6 And _
((InStr(str64, Chr(bytCode(i - 1))) - 1) And lngXX) = 0 Then
lngWrk = lngWrk + 1
lngFit = lngFit + (lngWrk * Multi_ByteWeight)
End If
lngWrk = 0
bln64 = False
Else
If bln64 = True Then
'BASE64ENCODE中
If InStr(str64, Chr(bytCode(i))) > 0 Then
lngBY = Int((lngWrk * 6) / 8)
lngXB = (lngWrk * 6) - (lngBY * 8)
lngXX = (2 ^ lngXB) - 1
lngWrk = lngWrk + 1
Else
lngWrk = 0
bln64 = False
End If
Else
'20-7E(1バイト目)
If (bytCode(i) >= &H20 And bytCode(i) <= &H7E) Then
lngFit = lngFit + (1 * SingleByteWeight)
'00-1F, 7F(1バイト目)
ElseIf (bytCode(i) >= &H0 And bytCode(i) <= &H1F) Or _
bytCode(i) = &H7F Then
lngFit = lngFit + (1 * SingleByteWeight)
End If
End If
End If
Next i
JudgeUTF7 = (lngFit * 100) / ((lngUB + 1) * Multi_ByteWeight)
End Function
'----UTF8関係
' 関数名 : JudgeUTF8
' 返り値 : 判定結果確率(%)
' 引き数 : bytCode : 判定文字データ
' : fixFlag : 確定判断有無
' 機能説明 : UTF8の文字コード判定(可能性)確率を計算する
' 備考 :
Private Function JudgeUTF8(ByRef bytCode() As Byte, _
Optional fixFlag As Boolean = False) As Long
Dim i As Long
Dim lngFit As Long
Dim lngUB As Long
lngUB = JUDGESIZEMAX - 1
If lngUB > UBound(bytCode()) Then
lngUB = UBound(bytCode())
End If
For i = 0 To lngUB
If fixFlag Then
'BOM
If bytCode(i) = &HEF Then
If i <= UBound(bytCode) - 2 Then
If bytCode(i + 1) = &HBB And _
bytCode(i + 2) = &HBF Then
JudgeUTF8 = JUDGEFIX_BOM
Exit Function
End If
End If
End If
End If
'AND FC(1バイト目) + 80-BF(2-6バイト目)
If (bytCode(i) And &HFC) = &HFC Then
If i <= UBound(bytCode) - 5 Then
If (bytCode(i + 1) >= &H80 And bytCode(i + 1) <= &HBF) And _
(bytCode(i + 2) >= &H80 And bytCode(i + 2) <= &HBF) And _
(bytCode(i + 3) >= &H80 And bytCode(i + 3) <= &HBF) And _
(bytCode(i + 4) >= &H80 And bytCode(i + 4) <= &HBF) And _
(bytCode(i + 5) >= &H80 And bytCode(i + 5) <= &HBF) Then
lngFit = lngFit + (6 * Multi_ByteWeight)
i = i + 5
End If
End If
'AND F8(1バイト目) + 80-BF(2-5バイト目)
ElseIf (bytCode(i) And &HF8) = &HF8 Then
If i <= UBound(bytCode) - 4 Then
If (bytCode(i + 1) >= &H80 And bytCode(i + 1) <= &HBF) And _
(bytCode(i + 2) >= &H80 And bytCode(i + 2) <= &HBF) And _
(bytCode(i + 3) >= &H80 And bytCode(i + 3) <= &HBF) And _
(bytCode(i + 4) >= &H80 And bytCode(i + 4) <= &HBF) Then
lngFit = lngFit + (5 * Multi_ByteWeight)
i = i + 4
End If
End If
'AND F0(1バイト目) + 80-BF(2-4バイト目)
ElseIf (bytCode(i) And &HF0) = &HF0 Then
If i <= UBound(bytCode) - 3 Then
If (bytCode(i + 1) >= &H80 And bytCode(i + 1) <= &HBF) And _
(bytCode(i + 2) >= &H80 And bytCode(i + 2) <= &HBF) And _
(bytCode(i + 3) >= &H80 And bytCode(i + 3) <= &HBF) Then
lngFit = lngFit + (4 * Multi_ByteWeight)
i = i + 3
End If
End If
'AND E0(1バイト目) + 80-BF(2-3バイト目)
ElseIf (bytCode(i) And &HE0) = &HE0 Then
If i <= UBound(bytCode) - 2 Then
If (bytCode(i + 1) >= &H80 And bytCode(i + 1) <= &HBF) And _
(bytCode(i + 2) >= &H80 And bytCode(i + 2) <= &HBF) Then
lngFit = lngFit + (3 * Multi_ByteWeight)
i = i + 2
End If
End If
'AND C0(1バイト目) + 80-BF(2バイト目)
ElseIf (bytCode(i) And &HC0) = &HC0 Then
If i <= UBound(bytCode) - 1 Then
If (bytCode(i + 1) >= &H80 And bytCode(i + 1) <= &HBF) Then
lngFit = lngFit + (2 * Multi_ByteWeight)
i = i + 1
End If
End If
'20-7E(1バイト目)
ElseIf (bytCode(i) >= &H20 And bytCode(i) <= &H7E) Then
lngFit = lngFit + (1 * SingleByteWeight)
'00-1F, 7F(1バイト目)
ElseIf (bytCode(i) >= &H0 And bytCode(i) <= &H1F) Or _
bytCode(i) = &H7F Then
lngFit = lngFit + (1 * SingleByteWeight)
End If
Next i
JudgeUTF8 = (lngFit * 100) / ((lngUB + 1) * Multi_ByteWeight)
End Function
'****************************************************************************
'以下のコードは自分のオリジナルになります
'****************************************************************************
public Function getLines(filePath As String) As String()
Dim obj As Object
Set obj = CreateObject("ADODB.Stream")
'まずは判定のためにバイナリモードで取得する
Dim bytCode() As Byte
With obj
.Open
.Type = 1
.LoadFromFile (filePath)
bytCode = .read
.Close
End With
'取得したバイト配列を使用して文字コードの判定を行う
Dim charSet As String
charSet = JudgeCode(bytCode)
Set obj = CreateObject("ADODB.Stream")
obj.charSet = charSet
Dim buf As String
With obj
.Open
.LoadFromFile (filePath)
buf = .ReadText
.Close
End With
If InStr(buf, vbCrLf) > 0 Then
getLines = Split(buf, vbCrLf)
ElseIf InStr(buf, vbLf) > 0 Then
getLines = Split(buf, vbLf)
Else
getLines = Split(buf, "")
End If
End Function
使用例は以下となります。
Sub test()
Dim s() As String
s = getLines("C:\Users\namek\Desktop\新規 テキスト ドキュメント.txt")
Dim i As Long
For i = 0 To UBound(s)
Debug.Print (s(i))
Next i
End Sub
自分の作ったgetLines関数について説明すると、まずバイナリデータとしてファイルを開いてバイト配列を取り出します。
そのバイト配列を使用して、参照先サイトの方が作成した文字コードを判別する関数を呼び出します。
そして、その結果を元にファイルをテキストデータとして読み込みます。
都合、ファイルを2回読み込むことになるのがネックなんですが、1回で対応するとコンバートの処理分岐を書いていくことになるのでしんどいです。
大変助かりました。
業務での活用やVBAの勉強ブログ執筆で検索しておりました。
ありがとうございました。
著作権等配慮したうえで、ブログ記事執筆にあたりリンクを貼らせていただいてもよろしいでしょうか?
コメントありがとうございます。
このブログへのリンクや自分のブログ独自のソースの転載は大丈夫です。(むしろめちゃくちゃありがたいです。)
メインのソースに以下のブログの方のものを改変しているので、一言書いて頂きたいです。
http://nonsoft.la.coocan.jp/SoftSample/SampleModJUDG.html
いかが使用条件みたいです。
‘ 使用条件 : このサイトの内容を使用(流用/改変/転載/等全て)した成果物を不特定
‘ : 多数に公開/配布する場合は、このサイトを参考にした旨を記述してく
‘ : ださい。(例)WEBページやReadMeにリンクを貼ってください
承知しました。有難うございました!
61行目の下記記述は間違っているような気がします。
If lngSJIS >= JUDGEFIX Then JudgeCode = “Shift_JIS: Exit Function”
ご指摘の通りダブルクォーテーションの位置がおかしかったので修正しておきました。
ありがとうございます。
文字コード対策で、とても難儀しているところで、このサイトに出会いました。有用なコード、感謝いたします。
良記事、ありがとうございます。
自動判定が安定せず苦しんでいましたが
「ADODB.Streamの自動判定は使えない」の一声で
またMSにやられていたのかと納得しました。
JISコード判定処理のところでコメントは2・3バイト目となっていますが実際は3バイト目の判定ができていないようです。
’28 42(2・3バイト目)
If bytCode(i + 1) = &H28 And bytCode(i + 1) <= &H42 Then