あどけない話

インターネットに関する技術的な話など

GHC と UTF-8

GHC が、どう UTF-8 を扱うか調べてみました。

コードへの埋め込み

文字列リテラルUTF-8 が使えました。

str = " システム "

どう扱っているのか、確かめてみます。

import Data.Char
map ord str → [32,12471,12473,12486,12512,32]

Char は1バイトではなく、UTF-8 の文字が収容できる大きさになっているようです。うまくできていますね。

UTF-8 ファイルの読み込み

UTF-8 で " システム " と書いたファイルを用意し、以下のコードを実行して、読み込ませます。

main = do cs <- getContents
          print $ map ord cs

結果は、こうなりました。

→ [32,227,130,183,227,130,185,227,131,134,227,131,160,32]

単なるバイトストーリムとして扱っているのが分ります。

ここで、以下のような先頭と末尾の空白を削るコードを考えます。

import Data.Char
strip = reverse. dropWhile isSpace . reverse . dropWhile isSpace
main = do cs <- getContents
          print $ map ord $ strip cs

このコードは、以下のように問題を起こします。

→ [227,130,183,227,130,185,227,131,134,227,131]

「ム」の3バイト目である 160 が削られています。原因は、isSpace が Non-breaking space (160) に対し、True を返すからです。

これを解決するためには、utf8-string というパッケージを入れるとよいようです。

import Data.Char
import qualified System.IO.UTF8 as U8
strip = reverse. dropWhile isSpace . reverse . dropWhile isSpace
main = do cs <- U8.getContents
          print $ map ord $ strip cs

実行すると、こうなります。

→ [12471,12473,12486,12512]

まとめ

Char が UTF-8 を収容できるように作られているのは、素敵ですね。