HaskellのOverloadedStringsでByteStringを作るとマルチバイトを切り捨てる罠があります
ずっと前に知っていたのですが, 頻繁に忘却するので記事にすることにしました.
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString.UTF8 as U
main :: IO ()
main = do
putStrLn $ U.toString "あ" -- B
putStrLn $ U.toString (U.fromString "あ") -- あ
以上.
HaskellのOverloadedStrings
は文字列のエンコードを規定していないのでマルチバイト文字を受け取ると適当に丸めてByteString
にします.
もちろん既出です.
文字列リテラルで指定されたマルチバイト文字を無理やりByteStringで扱おうとすると、特にエラーも出さず間違った結果を返すので注意が必要ですね。なので、ByteStringは文字列というよりは、生のバイト列を収めるデータ型と思ったほうが良いと思います。
この場合"マルチバイト"と言うのは正しいのだろうか… マルチバイト警察が怖い. 多分正しい.
今回cassavaでCSVファイルを作る時に他の人が「日本語が化ける」と言っていて確かに化けるのでcassavaにissueを建てるところでした. 気がつけて良かった.
マルチバイト文字列をByteString
にする時はstring-transformを使います.
内部でutf8-stringを使っています.
しかしこれ, 明らかに罠ですよね. コンパイルエラーにするのが他のエンコードや互換性の問題上難しいとして, 警告は出したほうが良さそうです. GHCのチケットを作りますか? これを見た英語が達者な人がチケットを作ってくれても良いですね.