DOBON.NET DOBON.NETプログラミング掲示板過去ログ

文字コードについて

分類:[.NET]

いま、VB.NET 2002でテキストエディタみたいなものを作成しています。

テキストを読み込むときに、そのテキストの文字コード(UTF8,JIS,EUC等)はどのように判断・判別したらいいのでしょうか?
.NET FrameWorkにそのようなメソッドがあるのでしょうか?
ないなら、具体的にどのようにしたらいいか教えて頂けないでしょうか。

よろしくお願いします。
■No1733に返信(naoさんの記事)
> テキストを読み込むときに、そのテキストの文字コード(UTF8,JIS,EUC等)はどのように判断・判別したらいいのでしょうか?

.NET Frameworkに文字コードを判別する方法は用意されていません。つまり、外部アプリに頼るか、自力で解決するかということになるでしょう。

他力ということで言うと、例えば、mlang.dllのIMultiLanguage2::DetectInputCodepageを使う手が考えられます。しかしこれも結構大変かもしれません。

・IMultiLanguage2::DetectInputCodepage Method
http://msdn.microsoft.com/workshop/misc/mlang/reference/ifaces/imultilanguage2/detectinputcodepage.asp

自力で解決するとなると文字コードに関する知識が必要になりそうですが、残念ながら私にはありません。そこで、Jcode.pmのgetcodeメソッドを参考にさせていただき(というより移植したつもり)、以下のようなコードを書いて見ました。果たして正確に移植されているのか、自信は全くありませんが、テストしたところでは、うまく行っているような気がします。どんなもんでしょうか?

・Jcode.pm
http://openlab.ring.gr.jp/Jcode/index-j.html

---------------------ここから
'/ <summary>
'/ 文字コードを判別する
'/ </summary>
'/ <remarks>
'/ Jcode.pmのgetcodeメソッドを移植したものです。
'/ Jcode.pm(http://openlab.ring.gr.jp/Jcode/index-j.html)
'/ Jcode.pmのCopyright : Copyright 1999 Dan Kogai.
'/ </remarks>
'/ <param name="byts">文字コードを調べるデータ</param>
'/ <returns>適当と思われるEncodingオブジェクト。
'/ 判断できなかった時はnull。</returns>
Private Function GetCode(ByVal byts() As Byte) As System.Text.Encoding
Const bESC As Byte = &H1B
Const bAT As Byte = &H40
Const bDollar As Byte = &H24
Const bAnd As Byte = &H26
Const bOP As Byte = &H28 '(
Const bB As Byte = &H42
Const bD As Byte = &H44
Const bJ As Byte = &H4A
Const bI As Byte = &H49

Dim len As Integer = byts.Length
Dim [binary] As Integer = 0
Dim ucs2 As Integer = 0
Dim sjis As Integer = 0
Dim euc As Integer = 0
Dim utf8 As Integer = 0
Dim b1, b2 As Byte

Dim i As Integer
For i = 0 To len - 1
If byts(i) <= &H6 OrElse byts(i) = &H7F OrElse byts(i) = &HFF Then
''binary'
[binary] += 1
If len - 1 > i AndAlso _
byts(i) = &H0 AndAlso byts(i - 1) <= &H7F Then
'smells like raw unicode
ucs2 += 1
End If
End If
Next i

If [binary] > 0 Then
If ucs2 > 0 Then
'JIS
'ucs2(Unicode)
Return System.Text.Encoding.Unicode
'binary
Else
Return Nothing
End If
End If

For i = 0 To len - 2
b1 = byts(i)
b2 = byts(i + 1)

If b1 = bESC Then
If b2 >= &H80 Then
'not Japanese
'ASCII
Return System.Text.Encoding.ASCII
Else
If len - 2 > i AndAlso _
b2 = bDollar AndAlso byts(i + 2) = bAT Then
'JIS_0208 1978
'JIS
Return System.Text.Encoding.GetEncoding(50220)
ElseIf len - 2 > i AndAlso _
b2 = bDollar AndAlso byts(i + 2) = bB Then
'JIS_0208 1983
'JIS
Return System.Text.Encoding.GetEncoding(50220)
ElseIf len - 5 > i AndAlso _
b2 = bAnd AndAlso byts(i + 2) = bAT AndAlso _
byts(i + 3) = bESC AndAlso byts(i + 4) = bDollar AndAlso _
byts((i + 5)) = bB Then
'JIS_0208 1990
'JIS
Return System.Text.Encoding.GetEncoding(50220)
ElseIf len - 3 > i AndAlso _
b2 = bDollar AndAlso byts(i + 2) = bOP AndAlso _
byts(i + 3) = bD Then
'JIS_0212
'JIS
Return System.Text.Encoding.GetEncoding(50220)
ElseIf len - 2 > i AndAlso b2 = bOP AndAlso _
(byts(i + 2) = bB OrElse byts(i + 2) = bJ) Then
'JIS_ASC
'JIS
Return System.Text.Encoding.GetEncoding(50220)
ElseIf len - 2 > i AndAlso _
b2 = bOP AndAlso byts(i + 2) = bI Then
'JIS_KANA
'JIS
Return System.Text.Encoding.GetEncoding(50220)
End If
End If
End If
Next i

For i = 0 To len - 2
b1 = byts(i)
b2 = byts(i + 1)
If ((b1 >= &H81 AndAlso b1 <= &H9F) OrElse _
(b1 >= &HE0 AndAlso b1 <= &HFC)) AndAlso _
((b2 >= &H40 AndAlso b2 <= &H7E) OrElse _
(b2 >= &H80 AndAlso b2 <= &HFC)) Then
sjis += 2
i += 1
End If
Next i

For i = 0 To len - 2
b1 = byts(i)
b2 = byts(i + 1)
If ((b1 >= &HA1 AndAlso b1 <= &HFE) AndAlso _
(b2 >= &HA1 AndAlso b2 <= &HFE)) OrElse _
(b1 = &H8E AndAlso (b2 >= &HA1 AndAlso b2 <= &HDF)) Then
euc += 2
i += 1
ElseIf len - 2 > i AndAlso b1 = &H8E AndAlso _
(b2 >= &HA1 AndAlso b2 <= &HFE) AndAlso _
(byts(i + 2) >= &HA1 AndAlso byts(i + 2) <= &HFE) Then
euc += 3
i += 2
End If
Next i

For i = 0 To len - 2
b1 = byts(i)
b2 = byts(i + 1)
If (b1 >= &HC0 AndAlso b1 <= &HDF) AndAlso _
(b2 >= &H80 AndAlso b2 <= &HBF) Then
utf8 += 2
i += 1
ElseIf len - 2 > i AndAlso _
(b1 >= &HE0 AndAlso b1 <= &HEF) AndAlso _
(b2 >= &H80 AndAlso b2 <= &HBF) AndAlso _
(byts(i + 2) >= &H80 AndAlso byts(i + 2) <= &HBF) Then
utf8 += 3
i += 2
End If
Next i

If euc > sjis AndAlso euc > utf8 Then
'EUC
Return System.Text.Encoding.GetEncoding(51932)
ElseIf sjis > euc AndAlso sjis > utf8 Then
'SJIS
Return System.Text.Encoding.GetEncoding(932)
ElseIf utf8 > euc AndAlso utf8 > sjis Then
'UTF8
Return System.Text.Encoding.UTF8
End If
Return Nothing
End Function
管理人さん わざわざありがとうございます。

ためしに下のようなのを書いてみて動作を確かめようとしたのですが、
何度やってもnullが返されてしまいます。
どこが間違っているのでしょうか。
初心者で申し訳ありません。

Dim path As String
Dim s As StreamReader
If OpenFileDialog1.ShowDialog = DialogResult.OK Then
path = OpenFileDialog1.FileName
s = New StreamReader(path)
Dim text As String = s.ReadToEnd
s = New StreamReader(path, GetCode(System.Text.Encoding.ASCII.GetBytes(text)))
TextBox1.Text = s.ReadToEnd
Else
Exit Sub
End If
■No1830に返信(naoさんの記事)
> ためしに下のようなのを書いてみて動作を確かめようとしたのですが、
> 何度やってもnullが返されてしまいます。

> s = New StreamReader(path, GetCode(System.Text.Encoding.ASCII.GetBytes(text)))

Encodingを使ってファイルを読み込んだのでは意味がありません。ファイルの読み込みは例えば次のようにしてください。

'ファイルを読み込む
Dim fsIn As New System.IO.FileStream(path, _
System.IO.FileMode.Open, System.IO.FileAccess.Read)
'すべて読み込む
Dim bytesIn(fsIn.Length - 1) As Byte
fsIn.Read(bytesIn, 0, bytesIn.Length)
'閉じる
fsIn.Close()

文字列に変換するには、次のようになります。

Dim enc As System.Text.Encoding = GetCode(bytesIn)
TextBox1.Text = enc.GetString(bytesIn)
返信が大変遅くなって申し訳ありません。
管理人さんがおっしゃった通りにしたら、うまくうごきました。
ありがとうございました。
解決済みにチェックを入れるのを忘れてしまいました(^_^;
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板