多分かなり変わった方法を使用していると思う。
EUC は UNIX で使用されている文字コードだよね。ひらがな、カタカナ(全角・半角)、漢字、全角アルファベットは2バイト、半角文字は1バイトという規格になっているみたい。半角の数字やアルファベットは EUC も S-JIS も同じ。従ってこの部分は考慮する必要が無いね。問題はそれ以外の文字コードだね。上位バイトが &H7F より大きければ2バイト文字と見なしてよい。ここより2バイト文字について考えていくからそのつもりで。それでは、EUCとS-JISの文字コードを簡単に比較してみよう。まず、1バイト目を見ると、次のようになっている。
EUC |
S-JIS |
|
EUC |
S-JIS |
&HA1 |
&H81 |
&HDF |
&HE0 |
&HA2 |
&H81 |
&HE0 |
&HE0 |
&HA3 |
&H82 |
&HE1 |
&HE1 |
&HA4 |
&H82 |
&HE2 |
&HE1 |
&HA5 |
&H83 |
&HE3 |
&HE2 |
&HA6 |
&H83 |
&HE4 |
&HE2 |
省略 |
省略 |
省略 |
省略 |
&HDD |
&H9F |
&HFD |
&HEF |
&HDE |
&H9F |
&HFE |
&HEF |
EUCコード &HDE と &HDF を境にして、S-JISコードが &H9F から &HE0 に数が飛んでいる所に注意してね。
見ての通り、EUCコード&HA1、&HA2 に対応するS-JISコードは&H81。同様に、EUCコード&HA3、&HA4 に対応するS-JISコードは&H82。まずはプログラムでこれをどう認識させるか考えてみよう。ここでは Windows上で動くかすこと考慮しているということが重要。即ち EUC 文字列は、Windows上では結局 S-JIS として保持されるんだよね。従って、EUC と S-JIS の文字コードの差分を求めて、Windows上のS-JIS(本当はEUC)コードから引いてあげればよい。さて、さて…。EUC増分2に対し、S-JISの増分は1でこれは不変、というところに目を付けよう。これは数列で処理できそうだね、しかも等差数列、簡単や。EUCコードを基準にして、上位バイトが偶数か奇数かを見る。奇数であれば、(EUC, S-JIS) (&HA1, &H81), (&HA3, &H82), (&HA5, &H83) … というようになっていく。さて、これを数式で表すと、
S-JIS上位バイト = 0.5(EUC上位バイト - &HA0) + 128.5
途中計算・公式の説明は割愛するよ。この要領で上位バイト処理を処理する数式を一気に書いちゃおう。
◎上位バイトが奇数 の時
・上位バイト < &HDF の時
S-JIS上位バイト = 0.5(EUC上位バイト - &HA0) + 128.5
・上位バイト ≧ &HDF の時
S-JIS上位バイト = 0.5(EUC上位バイト - &HDE) + 223.5
◎上位バイトが偶数 の時
・上位バイト < &HDF の時
S-JIS上位バイト = 0.5(EUC上位バイト - &HA0) + 128
・上位バイト > &HDF の時 (上位バイト = &HDF はありえない)
S-JIS上位バイト = 0.5(EUC上位バイト - &HDE) + 223
これでよろしい。何がなんだか分からない方は読み飛ばしちゃっても大丈夫です。用は動けばいいんだから。最後に半角カナについて触れておくね。半角カナは、上位バイトが &H8E のとき、下位バイトが半角カナのコードとなるんだよね。以上が上位バイトの変換方法だよ。さて次は、下位バイトや。下位バイトは、上位バイトが偶数か奇数かで処理が異なる。簡単だけど、文字コードを載せておくね。
上位バイトが奇数 |
|
上位バイトが偶数 |
EUC |
S-JIS |
EUC |
S-JIS |
&HA1 |
&H40 |
&HA1 |
&H9F |
&HA2 |
&H41 |
&HA2 |
&HA0 |
&HA3 |
&H42 |
&HA3 |
&HA1 |
省略 |
省略 |
省略 |
省略 |
&HDF |
&H7E |
&HDF |
&HDD |
&HE0 |
&H80 |
&HE0 |
&HDE |
&HE1 |
&H81 |
&HE1 |
&HDF |
省略 |
省略 |
省略 |
省略 |
&HFD |
&H9D |
&HFD |
&HFB |
&HFE |
&H9E |
&HFE |
&HFC |
ここでも注意する部分がある。なんと、上位バイトが奇数の場合、下位バイトは &H7F が存在しないのである。よう分からない規格だね。本当にこの点は注意!! んじゃぁ、簡単にまとめてみよう。
◎上位バイトが奇数 の時
S-JIS下位バイト = EUC下位バイト - &H61
この時、S-JIS下位バイト > &H7E であれば、
S-JIS下位バイトをインクリメント(1足す)する。
◎上位バイトが偶数 の時
S-JIS下位バイト = EUC下位バイト - &H2
あと、よく分かんないんだけれど、改行コードについてもう1つ。EUCではキャッジリターンが無くて、ラインフィードがあるケースがあるみたい。これについても対応しといたからね。いらないと思ったら取っちゃいましょう。
はあはあ、疲れた。でもまだコーディングが残ってるね。じゃあ、早速といいたい所だけどコーディングしていたら不都合な局面に遭遇したんだよね。文字列変数に EUC 文字列を格納させ、関数を作ったんだけど、バイトデータが変更されてしまっている!!という状況に陥った。SJISの何でこのようなことが言えるのかというと、ファイルから読み込んだらばっちり変換されたからだよ。
例えばこの文字列、"・キ・ケ・ニ・・"。SJISでは「システム"」という文字列だよ。ファイルから読みこむと、
上位 下位 変換前 変換後
A5 B7 シ シ
A5 B9 ス ス
A5 C6 テ テ
A5 E0 ム ム
22 0 " "
文字列変数に保持させて変換すると、
上位 下位 変換前 変換後
A5 B7 シ シ
A5 B9 ス ス
A5 C6 テ テ
A5 81 ム ・
45 0 " ?(壊れた文字)
となってしまう。「システ」までは正しく変換できるんだけど「ム」の下位バイトと「"」の上位バイトが変わってしまってるんだよね。Unicode がいけないのかと思い、Cでコーディングしたんだけど結果は同じだった。いや、わからん、わからん。
私のあらゆる知識(まだほんの少しだけど)をつぎ込んで正しい文字コードを取得しようとしたんだけど駄目だった。しょぼん。このようなことがあり、結局、ファイルから読み込むという方法で変換するようにしてしまった。トホホ。それでは、コードを載せましましょ。
'-----------------------------------------------------------
' 関数名: EucToSJis
' 機能 : EUCコードをS-JISコードに変換する
' 引数 : (in) srcFileName … ファイル名(変換前)
' (in) dstFileName … ファイル名(変換後)
' 返り値: なし
'-----------------------------------------------------------
Public Sub EucToSJis(ByVal srcFileName As String, ByVal dstFileName As String)
Dim srcBinLen As String '変換前文字列バイト数
Dim gHighASC As Byte 'Unicode文字1バイト目の値(上位)
Dim gLowASC As Byte 'Unicode文字2バイト目の値(下位)
Dim i As Long '作業用
Dim PreBinBuff() As Byte '変換前のバイトデータ
Dim BinBuffMain() As Byte '変換後のバイトデータ
Dim BinIndex As Long 'BinBuffMain のインデックス
Dim FileNum As Integer 'ファイルナンバー
On Error GoTo ErrHandler
'ファイルナンバー取得
FileNum = FreeFile
'ファイル読み込み
Open srcFileName For Binary Access Read As #FileNum
srcBinLen = LOF(FileNum) 'ファイルサイズ取得
ReDim Preserve PreBinBuff(srcBinLen + 1) As Byte
ReDim Preserve BinBuffMain(srcBinLen * 2) As Byte
Get #FileNum, , PreBinBuff
Close #FileNum
'1バイト分余分にループ
For i = 0 To srcBinLen
'アスキーコードを取得
gHighASC = PreBinBuff(i) '上位
gLowASC = PreBinBuff(i + 1) '下位
'2バイト文字である
If gHighASC > &H7F Then
'半角カナである
If gHighASC = &H8E Then
BinBuffMain(BinIndex) = gLowASC
BinIndex = BinIndex + 1
'ひらがな・漢字
Else
'1バイト目変換
'偶数である
If (gHighASC Mod 2) = 0 Then
Select Case gHighASC
Case Is < &HDF
BinBuffMain(BinIndex) = 0.5 * (gHighASC - &HA0) + 128
BinBuffMain(BinIndex) = 0.5 * gHighASC + 48
Case &HE0 To &HFE
BinBuffMain(BinIndex) = 0.5 * (gHighASC - &HDE) + 223
BinBuffMain(BinIndex) = 0.5 * gHighASC + 112
'Case Else
'ありえない
End Select
'奇数である
Else
Select Case gHighASC
Case Is < &HDF
BinBuffMain(BinIndex) = 0.5 * (gHighASC - &HA0) + 128.5
BinBuffMain(BinIndex) = 0.5 * gHighASC + 48.5
Case &HDF To &HFD
BinBuffMain(BinIndex) = 0.5 * (gHighASC - &HDE) + 223.5
BinBuffMain(BinIndex) = 0.5 * gHighASC + 112.5
'Case Else
'ありえない
End Select
End If
'2バイト目変換
'1バイト目が偶数である
If (gHighASC Mod 2) = 0 Then
BinBuffMain(BinIndex + 1) = gLowASC - &H2
'1バイト目が奇数である
Else
BinBuffMain(BinIndex + 1) = gLowASC - &H61
If BinBuffMain(BinIndex + 1) > &H7E Then
BinBuffMain(BinIndex + 1) = BinBuffMain(BinIndex + 1) + 1
End If
End If
BinIndex = BinIndex + 2
End If
'1バイト分進める
i = i + 1
'半角文字である
Else
'上位バイトがキャリッジリターン
'下位バイトがラインフィードである
If gHighASC = &HD And gLowASC = &HA Then
BinBuffMain(BinIndex) = &HD
BinBuffMain(BinIndex + 1) = &HA
BinIndex = BinIndex + 2
i = i + 1
'上位バイトがラインフィードである
ElseIf gHighASC = &HA Then
BinBuffMain(BinIndex) = &HD
BinBuffMain(BinIndex + 1) = &HA
BinIndex = BinIndex + 2
'ラインフィードでない半角文字である
Else
'上位バイトがキャリッジリターンである
If gHighASC = &HD Then
BinBuffMain(BinIndex) = &HD
BinBuffMain(BinIndex + 1) = &HA
BinIndex = BinIndex + 2
Else
BinBuffMain(BinIndex) = gHighASC
BinIndex = BinIndex + 1
End If
End If
'下位バイトがラインフィードである
If gLowASC = &HA Then
'上位バイトがキャリッジリターンでない
If gHighASC <> &HD Then
BinBuffMain(BinIndex) = &HD
BinBuffMain(BinIndex + 1) = &HA
BinIndex = BinIndex + 2
i = i + 1
End If
End If
End If
Next i
'メモリー確保
ReDim Preserve BinBuffMain(BinIndex - 2) As Byte
'ファイルナンバー取得
FileNum = FreeFile
'ファイル書き込み
Open dstFileName For Binary Access Write As #FileNum
Put #FileNum, 1, BinBuffMain()
'Beep
Close #FileNum
Exit Sub
ErrHandler:
Call MsgBox("エラーNo." & Err.Number & vbCrLf & vbCrLf & _
Err.Description, vbExclamation, "EUC -> S-JIS変換 - エラー")
End Sub
こんな感じでよろしいかな。
なお、コード上の数式
BinBuffMain(BinIndex) = 0.5 * (gHighASC - &HA0) + 128
は、この先を計算して
BinBuffMain(BinIndex) = 0.5 * gHighASC + 48
とした方が処理としては速いよ。ここでのコードは上で挙げた数式に従って書いただけなんで、実際、使用するときは直してあげた方がいいと思うよ。
|