[三流君] −−> [ASPで遊ぶ、失敗する] −−> [バックナンバー一覧]
−−> No.99 UTF-8からSJISの変換処理(デコード)に挑戦してみた

UTF-8からSJISの変換処理(デコード)に挑戦してみた



本文(発行内容)


UTF-8からSJISの変換処理(デコード)に挑戦してみた

こんにちは、三流プログラマーのKen3です。

今回は、UTF-8からSJISの変換ルーチンを自作してみます。
いつもの三流的なアプローチなので、実際はアレンジして使ってください。

/* * 1.今回のキッカケ */

SJISからUTF-8の変換をボロボロになりながら作りました。 三流君ASP http://www.ken3.org/cgi-bin/test/test097-2.asp?DATA=%8EO%97%AC%8CNASP 娘。 http://www.ken3.org/cgi-bin/test/test097-3.asp?DATA=%96%BA%81B 転職 http://www.ken3.org/cgi-bin/test/test097-3.asp?DATA=%93%5D%90E など、自作のSJISからUTF-8の変換ルーチンを作って回しました。 今回は、逆の、UTF-8からSJISの変換ルーチンを自作してみます。 また、自作するの?encodeURIの逆、デコードURIは使わないの? ※自作が好きなんで・・・

/* * 2.UTF-8コード と 変換処理の構想 */

検索キーワード忘れましたが、 下記のようなコードの対応表を発見しました http://www.asahi-net.or.jp/~CI5M-NMR/w3/rfc2279.txt より UCS-4 range (hex.) UTF-8 octet sequence (binary) 0000 0000-0000 007F 0xxxxxxx 0000 0080-0000 07FF 110xxxxx 10xxxxxx 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx と、変換表(規則)が書いてあった。 ※binaryの単語で引っかかったと思う。 2バイト文字(漢字)は、 1110xxxx 10xxxxxx 10xxxxxx と、なります。 これを、xxの部分をまとめてると、UNIコードになるので、 それをCHRW関数でSJISに戻してます。 http://www.google.co.jp/search?q=%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB がファイルを指定してます。 %E3%83%95 フ %E3%82%A1 ァ %E3%82%A4 イ %E3%83%AB ル とUTF-8でコード付けされてます。 ファイルの[フ]がE3 83 95かぁこれを2進数に直すと。 E 3 8 3 9 5 1110 0011 1000 0011 1001 0101 となります。 ここから、 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx の規則でxxxxの実データを取り出すと(1110 10 10は固定のコードなので) E 3 8 3 9 5 1110 0011 1000 0011 1001 0101 xxxx xx xxxx xx xxxx から xの部分を取り出すと、 0011 00 0011 01 0101 となり、わかりやすく、 0011 0000 1101 0101 として16進に直すと 30D5となるが、これはUNICODEらしい。 これをシフトJISに変換すれば、 UTF-8のデータを取り出せそうです。

/* * 3.ログDBからUTF-8コードを変換してみた(サンプル作成) */

http://www.ken3.org/cgi-bin/cnt/log100.asp?MODE=ETC で、通販ページのログを取ってます。 このデータを変換して、検索キーワードを表示させてみたいと思います。 テストで上に元のgoogleの検索リンク、下に変換結果を作成しました http://www.ken3.org/cgi-bin/test/test099-1.asp でテスト可能です。 ソースとデータを見て確認してください。 <%@LANGUAGE=VBScript%> <html> <head> <title>文字コード関係で遊ぶ UTF-8からSJISへ変換(検索キーワードを戻す)</title> </head> <body> <h1>文字コード関係で遊ぶ UTF-8からSJISへ変換(検索キーワードを戻す)</h1> <br> ログファイルから、UTF-8のキーワードを戻してみます。<br> ※詳細は、ソースと詳細解説のページを見てください。<br> テストで上に元のgoogleの検索リンク、下に変換結果を作成しました<br> <hr> <% 'ADO DB Connection オブジェクトを作成 Set db=Server.CreateObject("ADODB.Connection") db.Provider = "Microsoft.Jet.OLEDB.4.0" '接続DBの位置を渡し、DBオープン strDB = "../test/cnt_etc.mdb" db.ConnectionString = Server.MapPath(strDB) db.open 'データベースをオープンする 'お約束のレコードセットの作成 テーブル名logから全項目(*)を指定 'UTF-8のデータをLikeで選択する strSQL = "Select * From log Where referrer Like '%UTF-8%' " strSQL = strSQL & " ORDER BY WriteTime DESC" Set rs = db.Execute(strSQL) 'データの表示を行う Response.Write "発行するSQL:" & strSQL & "<hr>" 'EOFまでループ or 10件まで nCNT = 1 Do While rs.EOF = False And nCNT <= 10 '.EOFがFalseで10以下の間 'リンク元の表示 Response.Write "変換前:<A HREF='" & rs.Fields.Item("referrer") & "'>" Response.Write rs.Fields.Item("referrer") & "</A><BR>" '%付のUTF-8コードを変換してみた Response.Write "変換後:" & KANJI_HENKAN(rs.Fields.Item("referrer")) Response.Write "<BR><BR><HR><BR>" '次のレコードにポインタを移動する rs.MoveNext 'これを忘れると悲惨なことに、、、 'カウンタを増やす nCNT = nCNT + 1 Loop '開いていたレコードセットを閉じる rs.Close 'データベースも閉じようよ db.Close 'お行儀よくオブジェクトも開放しましょう(通常は自動的に解放されるけど) Set db = Nothing 'テストで終了時刻の表示 Response.Write "終了:" & Now() & "<hr>" %> </body> </html> <% '変換サブルーチンをまとめる '%の後ろを強引に(手抜きで)変換してみた
Function KANJI_HENKAN(strMOJI)

  Dim strRET

  strRET = ""  'リターン値を初期化する

  '特殊文字を手抜きでReplace関数で置き換える
  strWORK = strMOJI
  strWORK = Replace(strWORK, "%3F", "?")
  strWORK = Replace(strWORK, "%2F", "/")
  strWORK = Replace(strWORK, "%3A", ":")
  strWORK = Replace(strWORK, "%3D", "=")
  strWORK = Replace(strWORK, "%26", "&")
  '+をスペースに変換したいけど、今回はそのまま。

  strMOJI = strWORK  '特殊文字変換結果の代入

  '文字単位でループする
  For n = 1 To Len(strMOJI)
     strCHK = Mid(strMOJI, n, 1) '1文字取り出す
     If strCHK = "%" Then  '%の後ろをデコードするかチェック
        strWORK = Mid(strMOJI, n, 9) '9文字取り出し変換処理へ渡す
        strRET = strRET & UTF8toSJIS(strWORK)  '変換結果を+する
        n = n + 8  '強引に8文字飛ばす
     Else  'そのまま
        strRET = strRET & strCHK  'そのまま+する
     End If
  Next

  KANJI_HENKAN = strRET

End Function
Function UTF8toSJIS(strCODE)

    '%E6%96%87 の UTF-8コード文字列をSJISに直す
    
    Dim strHEX
    Dim n      'ループカウンタ
    Dim i      'ループのカウンタ
    
    Dim str2CODE  '2進数の文字列
    Dim str2UNI   'UNICODE2進数
    
    '1コード目を変換
    strHEX = Mid(strCODE, 2, 2) '%を抜かしたコードを取得
    str2CODE = HEX16toSTR2(strHEX)
    
    '2コード目を変換
    strHEX = Mid(strCODE, 5, 2) '%を抜かしたコードを取得
    str2CODE = str2CODE & HEX16toSTR2(strHEX)
    
    '3コード目を変換
    strHEX = Mid(strCODE, 8, 2) '%を抜かしたコードを取得
    str2CODE = str2CODE & HEX16toSTR2(strHEX)
    
    'コードを抜き出しコピーする
    '0          1           2
    '1234 5678 9012 3456 7890 1234
    '1110 xxxx 10xx xxxx 10xx xxxx を下記に割り当てる
    'xxxx xxxx xxxx xxxx
    str2UNI = Mid(str2CODE, 5, 4)
    str2UNI = str2UNI & Mid(str2CODE, 11, 6)
    str2UNI = str2UNI & Mid(str2CODE, 19, 6)
    
    '作成した2進数を16進数に直す
    strHEX = STR2toHEX16(str2UNI)
    
    '16進数文字列を数値に直し、さらにChrW関数でSJISに
    UTF8toSJIS = ChrW(CInt("&H" & strHEX))

End Function
'HEX16進文字列を受け取り2進文字列を返す
Function HEX16toSTR2(strHEX)

    Dim n       'ループカウンタ
    Dim i       'ループのカウンタ
    Dim n8421   '8 4 2 1の数値計算用
    Dim str2STR
    
    Dim nCHK
    
    str2STR = ""  '結果のエリアを初期化する

    '文字数分ループする
    For n = 1 To Len(strHEX)
        nCHK = 0 '0で初期化
        On Error Resume Next 'エラーを無視する
        nCHK = CInt("&h" & Mid(strHEX, n, 1)) 'n文字目を数値変換
        On Error Goto 0
        n8421 = 8  '初期値に8を代入する(上からチェックしたいので)
        For i = 1 To 4  '4回まわるよ
            If (nCHK And n8421) = 0 Then 'Andでビットをチェックする
                str2STR = str2STR & "0"  'ビットは立ってないよ
            Else
                str2STR = str2STR & "1"  'ビットは立ってるよ
            End If
            '次のビットをチェックしたいので2で割る
            n8421 = n8421 / 2
        Next 
     Next 

     'リターン値をセットして終了
     HEX16toSTR2 = str2STR

End Function
'2進文字列を受け取り16進文字列を返す
Function STR2toHEX16(str2)

    Dim strHEX
    Dim n       'ループカウンタ
    Dim i       'ループのカウンタ
    Dim n8421   '8 4 2 1の数値計算用
    Dim nBYTE

    '頭4文字単位かチェックする
    n = Len(str2) Mod 4      '足りない文字数を計算する
    If n <> 0 Then 
       str2 = String(4 - n, "0") & str2 '頭に文字0を追加する
    End If

    strHEX = ""   '結果のエリアを初期化する

    '文字数分ループする
    For n = 1 To Len(str2) Step 4  '4文字(1バイト)単位にループを作る
        n8421 = 8  '初期値に8を代入する(上から計算したいので)
        nBYTE = 0  '1バイト計算用変数を初期化
        For i = 0 To 3  '4回まわるよ(4ビット分)
            'ビットが立っているかチェックする
            If Mid(str2, n + i, 1) = "1" Then
                nBYTE = nBYTE + n8421   'ビットに対応した数値を+する
            End If
            '次のビットを計算したいので2で割る
            n8421 = n8421 / 2
        Next 
        '計算して、1倍との数値が完成したので16進文字にしてセットする
        strHEX = strHEX & Hex(nBYTE)
     Next 

     'リターン値をセットして関数を抜ける
     STR2toHEX16 = strHEX

End Function
%>

/* * 4.終わりの挨拶 </HTML> */

今回は、%付のUTF-8コードを戻してみました。 これで、ログで収集したGoogleからの来場者が使用したキーワードがわかりそうです。 ほかのコードも戻して、ログキーワード解析につなげたいですね。 無駄な部分多いですが、変換処理の一つの案として、受け取ってください。 何かの参考となれば幸いです。 ASP、VBScript勉強中の三流プログラマーのKen3でした。


ページフッター

ここまで、読んでいただきどうもです。目的の情報が見つかったか?少々心配しつつ、、、

三流君へ メッセージを送る

感想や質問・要望・苦情など 三流君へメッセージを送る。
返信例 XXXXさんへ
下記のフォームからメッセージを送ることができます。


あなたのお名前(ニックネーム):さん
返信は?:

アドレス:に返事をもらいたい
感想や質問↓:


(感想や質問・要望・苦情はHPで記事に載せることがあります。)

種類別のリンク や 広告など

[三流君(TOP ken3.org へ戻る)] / [ASPで遊ぶ、失敗する] / [ASP記事 バックナンバー目次]


Blogとリンク:[三流君のMemo別館]/ [ASP 三流君のソースコード置き場]/ [Ken3Video YouTubeで動画解説]
広告:

気になった ジャンル ↓を選択してください。

まぁ、基本はデータの受け取りかなぁ。
・[Form等を使用したデータのやり取り]・・・ASPと言っても、HTMLの入力フォームからデータを受け取ります。POSTやGETでやりとりを押さえますか。

次は、データの入出力 で ADOを使った(ADOで接続) と SQLの解説を少々
・[ADOでMdbファイルを使う]・・・MDBと接続して、簡単な追加・更新・削除を行った。
・[ADOでExcelと接続してみた]・・・.xlsと接続してSQLを使ってみた。
・[ADOでCSVと接続してみた]・・・.CSV テキストを読み出した。※更新・削除はできません

広告:



DBが使えるので、あまり使用しないけど、普通のテキストファイル処理
・[テキストファイル処理]・・・ファイルを開いて、書き込む。1行読み込みなどを軽く

VBScriptでFormat関数が無いなど、微妙にVBAと違うけど
[VBScript関数関係の説明]・・・少し、処理を書いてみた。
[その他処理サンプル]・・・あまり良いサンプル作れなかったけど。。。
何かの参考となれば幸いです。



[三流君(TOP ken3.org へ戻る)] / [ASPで遊ぶ、失敗する] / [ASP記事 バックナンバー目次]


広告: