aodama.gif(0.97KB) NKF32.DLL で文字コード変換

 海人さんが、 NKF(市川 至さん及び Shinji Kono さんらが作成された Network Kanji Filter)を Win32 DLL として移植された NKF32.DLL を使用すれば、 VBからでも簡単に文字コードを EUC-JP, JIS 等に変換できます。
 宣言モジュール内には、NKF32.DLL を実際に使用するサンプルなども書いてありますので参考にして下さい。

! 注意事項 !

 このモジュールは、海人さんが作成された NKF32.DLL にのみ対応しております!

海人さんのウェブサイト : http://hp.vector.co.jp/authors/VA002133/

 上記の海人さんのウェブサイトよりダウンロードできるもの以外の NKF32.DLL では 一切動作確認を行っておりませんので、ご注意下さい。
 なお、動作確認を行った最新のバージョンは "1.5k 1.03.32" です。

 他のバージョンにもそのうち対応したいとも思いますが、いかんせん時間が・・・。 まあ、そのうちきっと私のよりはるかに良いモジュールを誰かが作ってくれるでしょう・・・(^^;

Option Explicit

'===== NKF32.DLL Declaration Module for Visual Basic(32bit) Ver 1.07 =====
'(C)2000-2006 けるべ
'MAIL : NULL
'HOME : http://www.geocities.co.jp/SilkRoad/4511/
'
'このモジュールは、海人氏が NKF を Win32 用に移植された NKF32.DLL を、
'Microsoft Visual Basic(32bit) から使用するための宣言モジュールです。
'NKF32.DLL および NKF についての詳細は、NKF32.DLL に添付されている
'nkf32.doc をお読み下さい。
'
'海人さんのウェブサイト : http://hp.vector.co.jp/authors/VA002133/
'
'☆☆☆☆☆ 超重要注意事項 ☆☆☆☆☆
'
'このモジュールは、海人さんが作成された NKF32.DLL に「のみ」対応しております!
'上記の海人さんのウェブサイトよりダウンロードできるもの以外の NKF32.DLL では
'「一切」動作確認を行っておりませんので、ご注意下さい。
'なお、動作確認を行った最新のバージョンは "1.5k 1.03.32" です。
'
'宣言文についている関数説明はすべて nkf32.doc からの引用であり、
'海人さんが作成された NKF32.DLL に「のみ」適用可能なものです。
'他の方が作成された NKF32.DLL には適用されませんのでご注意下さい。
'
'なおこのモジュールには、NKF32.DLL の使用を簡単にするラッパー関数も
'含めてありますが、こちらは海人さんが作成された NKF32.DLL 以外のもので
'使用されることは一切考慮していません!
'また、あくまでも「サンプル」として含めましたので、
'広い範囲の用途で使用するには少々難があります。各自用途に応じた
'ラッパー関数を自作して下さい(^^;
'
'このモジュールの使用・転載は自由に行っていただいて結構ですが、
'NKF および NKF32.DLL については作成者の方々の条件に従って下さい。


'----- 2-1 NFK32 DLLのバージョンを返す -----
'書式    void CALLBACK GetNkfVersion(LPSTR verStr) ;
'解説    verStr  nkf移植元バージョン nkf32.dllバージョン(1.5k 1.03.32)を返します。
Public Declare Sub GetNkfVersion Lib "Nkf32.dll" _
    (ByVal verStr As String)

'----- 2-2 漢字変換オプションの指定 (NKF) -----
'書式    int CALLBACK SetNkfOption(LPCSTR optStr) ;
'戻値    エラー時は負値、正常終了時は0を戻します。
'解説    optStr  変換オプション文字列(-j -e -s -i? -o? -r -m -l -Z -J -E -S -X -B -x)
'        スペースとマイナスは無視しているので、連続したオプションの指定も可能です。
'        なお、オプションの詳細は、後述の「NKFオリジナルドキュメント」を参照して下さい。
'        例: "-iB -oJ -s -m"  "iBoJsm"  "iB oJ s m" (いずれも有効)
Public Declare Function SetNkfOption Lib "Nkf32.dll" _
    (ByVal optStr As String) As Long

'----- 2-3 漢字コード変換 (NKF) 行末コードの変換は行いません -----
'書式    void CALLBACK NkfConvert(LPSTR outStr, LPCSTR inStr) ;
'解説    outStr  出力文字列
'        inStr   入力文字列
Public Declare Sub NkfConvert Lib "Nkf32.dll" _
    (ByRef outStr As Any, _
     ByRef inStr As Any)

'----- 2-4 全角英数字・記号文字列を半角文字列に変換 -----
'書式    void CALLBACK ToHankaku(LPSTR inStr) ;
'解説    inStr   入力文字列。変換結果はinStrに格納します。
Public Declare Sub ToHankaku Lib "Nkf32.dll" _
    (ByRef inStr As Any)

'----- 2-5 半角カタカナと一部の記号(「」ー等)を全角カタカナに変換 -----
'書式    void CALLBACK ToZenkakuKana(LPSTR outStr ,LPCSTR inStr) ;
'解説    outStr  出力文字列
'        inStr   入力文字列
Public Declare Sub ToZenkakuKana Lib "Nkf32.dll" _
    (ByRef outStr As Any, _
     ByRef inStr As Any)

'----- 2-6 メールのサブジェクト(タイトル)をMIME(Base64)に変換 -----
'書式    void CALLBACK ToMime(LPSTR outStr ,LPCSTR inStr) ;
'解説    outStr  出力文字列
'        inStr   入力文字列
'SHIFT-JISのメールタイトルを変換する時は、JISに変換したあと、これをMIMEに変換して下さい。
'
'(※ 宣言モジュール作成者注)
'nkf32.doc においては ToMime とされていますが、NKF32.DLL には
'ToMime のエントリは存在せず、EncodeSubject となっています。
'この宣言モジュールでは EncodeSubject を参照していますが、
'今後 NKF32.DLL の仕様変更によっては ToMime に変更される可能性も
'ありますのでご注意下さい。
Public Declare Sub ToMime Lib "Nkf32.dll" Alias "EncodeSubject" _
    (ByRef outStr As Any, _
     ByRef inStr As Any)
     
Public Declare Sub EncodeSubject Lib "Nkf32.dll" _
    (ByRef outStr As Any, _
     ByRef inStr As Any)

NKF32.DLL Declaration Module for Visual Basic(32bit) : ダウンロード nkf32s.lzh(10.0KB)

 なお、このサンプルを動作させる前に、 海人さんのウェブサイトなどから NKF32.DLL を入手し、システムフォルダにコピーしておいて下さい。

 NKF32.DLL の VB からの使用方法およびこの宣言モジュール自体についての質問を、海人さんにしてはいけません(^^;

質問される前に勝手に Q&A

Q : 「バイト型配列」って何よ?

A :
 バイト(Byte)型配列は、連続したバイトデータの格納などによく使用されます。 バイナリファイルもバイト型配列を使用すれば、変数配列として取り込むことができます。 たとえば、こんな並び(16 進数)の 10 バイトのバイナリファイル("D:\Test\Test.bin")があったとします。

    4F 10 5A F2 B6 04 87 E5 32 81

(取り込む例)
Private Sub Command1_Click()

 Dim intFileNumber As Integer   'ファイルの空き番号を格納する変数
 Dim lngFileSize As Long        'ファイルサイズを格納する変数
 Dim bytArray() As Byte         'バイナリファイルの内容を格納するバイト型配列
 Dim i As Long                  'ただのループカウンタ
 
    intFileNumber = FreeFile                             '使用可能なファイル番号を得る
    Open "D:\Test\Test.bin" For Binary As #intFileNumber '"D:\Test\Test.bin" をバイナリモードで開く
    lngFileSize = LOF(intFileNumber)                     'LOF 関数でファイルサイズを得る
    If lngFileSize Then                                  'ファイルサイズが 0 以外だった場合
        ReDim bytArray(lngFileSize - 1)                  '配列サイズをファイルサイズ分確保
        Get #1, , bytArray                               'バイト型配列 bytArray にファイルからデータを読み込む
        For i = 0 To (lngFileSize - 1) Step 1            '配列の内容を 1 バイトずつ表示
            Debug.Print ; "bytArray(" & i & ") = &H" & Hex$(bytArray(i))
        Next i
    End If
    Close #intFileNumber                                 'ファイルを閉じる

End Sub

(実行結果)
bytArray(0) = &H4F
bytArray(1) = &H10
bytArray(2) = &H5A
bytArray(3) = &HF2
bytArray(4) = &HB6
bytArray(5) = &H4
bytArray(6) = &H87
bytArray(7) = &HE5
bytArray(8) = &H32
bytArray(9) = &H81
 で、文字列もバイトデータの集まりです。 たとえば "あいうえお" なら、Shift-JIS では
    82 A0 82 A2 82 A4 82 A6 82 A8
というバイトデータの並びで表現されています(10 バイト)。EUC では、
    A4 A2 A4 A4 A4 A6 A4 A8 A4 AA
で表現されます(10 バイト)。NKF は、これらの文字コードの違いを判別し、 指定した文字コードに変換してくれるものです。

 VB の文字列型(String)には Shift-JIS, EUC, JIS 等の文字列は格納できないので、 この宣言モジュールでは、文字列をバイナリデータと同じようにバイト型配列に取り込む仕様にしたのです。


Q : 文字列を渡せねえぞゴルァ

A :
 VB が文字列の内部処理に使用している文字コードは Unicode ですので、 Unicode を扱えない NKF32.DLL にそのまま渡しても処理できません。 そのため、文字列は Shift-JIS に変換してバイト型配列に格納してから処理する必要があります。

 Unicode → S-JIS の変換は VB の標準関数 StrConv で簡単にできます。簡単な変換例を書いておきます。

'----- UnicodeToSJIS -----
'VB 標準の Unicode 文字列を Shift-JIS に変換し、バイト型配列に格納します。
'
'引数 strUnicode
'   Shift-JIS に変換したい Unicode 文字列を指定します。
'
'引数 bytSjis()
'   Shift-JIS に変換した結果を格納するバイト型配列を指定します。
'
'戻り値
'   bytSjis() に格納したサイズ(最大要素数 + 1)を返します。
'   失敗した場合は 0 を返します。
'
Public Function UnicodeToSJIS(ByRef strUnicode As String, ByRef bytSjis() As Byte) As Long

 Dim lngSjisSize As Long 'S-JIS 変換後のサイズ
 
    'いったん文字列を S-JIS に変換し、そのサイズを求める
    lngSjisSize = LenB(StrConv(strUnicode, vbFromUnicode))
    If lngSjisSize Then 'サイズの取得に成功した場合
        'S-JIS 文字列を格納する領域を確保
        ReDim bytSjis(lngSjisSize - 1)
        'バイト型配列 bytSjis() に S-JIS 変換文字列を格納する
        bytSjis = StrConv(strUnicode, vbFromUnicode)
        UnicodeToSJIS = lngSjisSize '変換後サイズを返す
    End If

End Function
逆に Shift-JIS → Unicode の変換は、
    strUnicode = StrConv(bytSjis, vbUnicode)
とするだけです。基本的には Shift-JIS の文字列は VB では直接扱うことができませんので、 StrConv 関数などで Unicode に変換して下さい。 EUC, JIS は VB では全く読めません(泣)。文字コード変換が正常に行われたか確認したい場合は、 バイト型配列を Put ステートメントなどを使用してファイルとして保存し、 ブラウザや高機能なテキストエディタ(EmEditor, 秀丸など)で確認するといいでしょう。


Q : 半角カナを交えた文字列を渡すと文字化けするよ

A :
 よくネット上で「半角カナは使わないで下さい。文字化けします」と書かれているのを目にすると思いますが、 なぜ文字化けが発生するのかというと、Shift-JIS と EUC の間で半角カナの文字コードと2バイト文字のコードが一部重なっているためです。

 例えば半角カナ "コンニチハ" の S-JIS の文字コードは

コ  ン  ニ  チ  ハ
BA DD C6 C1 CA 
ですが、EUCで
 際    徳
BA DD C6 C1 CA 
とも読めてしまいます。NKF や jcode.pl のような文字コード判別&変換ルーチンはこの区別ができないため、 文字化けが発生するのです。 例えば掲示板投稿文のタイトルや文頭に半角カナが使用されていると、かなり高い確率で文字化けが発生します。

(化けにくい例)
ヽ(´ー`)ノマタリー ・・・ (2バイト文字 "ヽ" で判別できる)

(化けやすい例)
(^^;ワラ ・・・ (ANSI 半角英数字・記号は判別の対象にならないため、半角カナが判別対象になってしまう)

 ちなみに「NKF オリジナルドキュメント」には、

実は、入力のコード系の判定は、EUCとシフトJISとの自動判定であり、最初に
特定できる文字が来た時点で確定してしまう。そして、特定不能の間は保留バッ
ファにためておかれ、確定後に処理される。
と書かれています。やはり他のたいていの文字コード判別ルーチンも、 文字列の最初の方で文字コードを判別しています。 そのため掲示板への題名・ハンドル名・投稿文でも、 最初の方で半角カナを使わなければ、文字化けの発生率は減ります(笑)

 かつては Shift-JIS で記述されたウェブページが大半であり、ブラウザの文字化けもそれほど発生しなかったのですが、 近年は UTF-8 を使用したウェブページも増えてきているため、全般的に文字化け発生率が以前より高くなってきている気がします(泣)。 HTTP プロトコルにて HTML を公開する場合は必ず、 HTTP ヘッダあるいは META タグにて、文字コードを明示しておくべきでしょう。 (でも、俺もあまりやってないか・・・)


Q : 改行コードの変換はできないの?

A :
 テキストの改行コードの種類には、

CR      (&HD)       - Mac 標準     → vbCr
LF      (&HA)       - UNIX 標準    → vbLf
CR + LF (&HD + &HA) - Windows 標準 → vbCrLf
の三種類があり、Windows で正常に改行されるようにするには、改行コードを CR + LF にしなければなりません。 NKF32.DLL だけではこの改行コードを変換することはできませんので、 自分でループを回すなどしてゴリゴリ変換してやるしかありません(^^;

 NKF32.DLL Declaration Module for Visual Basic(32bit) Ver 1.08 以降より、 ReturnCodeConv 関数を追加しました。 いわゆる、単にループを回して改行コードをゴリゴリ変換する手抜き関数です(笑)。 RtlMoveMemory() とかで配列コピーすれば高速に置換できることはわかっているのですが、面倒だったので。 ただしバイト型配列に格納されたテキストに対してのみ使用できる関数ですので、 Unicode である VB 標準の文字列型変数(String 型)には直接使用できません。

 あまり効率の良い方法ではありませんが、Unicode に変換した後に、 文字列置換関数(Replace 関数)で vbCr または vbLf を vbCrLf に変換してやるという手もあります。 ただしその方法を用いる場合において、異なる改行コードが混在している場合は、 このような順序で行わないといけません。

すべての vbCrLf を vbLf に変換  例 :
strResult = Replace(strResult, vbCrLf, vbLf)
すべての vbCr を vbLf に変換  例 :
strResult = Replace(strResult, vbCr, vbLf)
すべての vbLf を vbCrLf に変換  例 :
strResult = Replace(strResult, vbLf, vbCrLf)

 上に書いたような方法を用いずに単純に vbCr および vbLf を vbCrLf に置換した場合、 文字列中に vbCrLf が存在していると、その vbCrLf は vbCrLf & vbCrLf(改行コードの連続) に変換されてしまう危険性があります。 なぜなら文字列置換関数は vbCrLf 中の vbCr および vbLf を単一の文字として認識し置換してしまうためです。

参考 : 文字列の置き換えをする(Replace)


VBコーナーにもどる   トップページにもどる