EUC-JPエンコードと戦う

webからhtmlデータをとってHaskellで解析しようとしたのだけど、対象のhtmlがEUC-JPエンコードでなかなかうまくいかない。仕方ないので、

  1. wgetを使ったshellスクリプトHaskellプログラムで吐き出す
  2. そのshellスクリプトをコンソールから起動して、ファイルに保存
  3. 同時にshellスクリプト中でiconvコマンドでUTF-8に変換
  4. ファイルをHaskellプログラムで開いて解析

という手順をとることにした。そんなことするくらいなら、PythonとかPerlで良いんじゃね? という気もしないではないけど、これで順調に動いていた。

ところが、新しく欲しくなったhtmlデータのURIEUC-JPでURIエンコードされている。これに困った。ウキーとなった。

結局、URIエンコードするコマンドをHaskellで書いて、それを上記shellスクリプトのなかで呼び出すことすることにする:

module Main where

import Data.ByteString.Lazy as BS (getContents, unpack) 
import Codec.Text.IConv
import Text.Printf
import Data.Char
import System

main = do
  args <- getArgs
  bs <- BS.getContents
  putStr $ f $ unpack $ convert "UTF-8" (args!!0) bs
  where
    f l = concat $ map g l
    g w = map toUpper $ printf "%%%02x" w

これを「ghc --make UriEscape.hs」でコンパイルしておいて、Haskellプログラムでつぎのようなshellスクリプトを吐かせる:

#!/bin/sh

wget -O - http://xx.jp/xx.cgi?v=`echo ほげ | ./UriEscape EUC-JP` | iconv -f EUC-JP -t UTF-8 | sed 's/EUC-JP/UTF-8/' > foo.html
wget -O - http://xx.jp/xx.cgi?v=`echo ふが | ./UriEscape EUC-JP` | iconv -f EUC-JP -t UTF-8 | sed 's/EUC-JP/UTF-8/' > bar.html

で、その後、foo.htmlとかbar.htmlとかを開いて解析。

(追記)
ちょっと改良:

  • printfに「x」ではなく「X」を使えば、toUpperはいらない
  • コードを整理
  • echoに「-n」をつけないと改行がゴミとして混じる
module Main where

import Data.ByteString.Lazy as BS (getContents, unpack) 
import Codec.Text.IConv
import Text.Printf
import System

main = do
  args <- getArgs
  bs <- BS.getContents
  putStr $ conv (args!!0) bs

conv to = concat . map (printf "%%%02X") . unpack . convert "UTF-8" to
#!/bin/sh

wget -O - http://xx.jp/xx.cgi?v=`echo -n ほげ | ./UriEscape EUC-JP` | iconv -f EUC-JP -t UTF-8 | sed 's/EUC-JP/UTF-8/' > foo.html
wget -O - http://xx.jp/xx.cgi?v=`echo -n ふが | ./UriEscape EUC-JP` | iconv -f EUC-JP -t UTF-8 | sed 's/EUC-JP/UTF-8/' > bar.html