Haskellの文字について
文字の取扱いでいつも忘れてしまうのでメモ
String
内部的には Unicodeポイント で保存、大量データには不向き、低速。
Prelude> let v1 = "あああ"
Prelude> v1
"\12354\12354\12354"
\12354(U+3042) はUnicodeポイント
Text
内部的には Unicodeスカラ値 で保存、大量データ向き、高速、マルチバイト文字を扱える、日本語はこちらを利用。
Prelude Data.Text> let v1 = pack "あああ"
Prelude Data.Text> v1
"\12354\12354\12354"
Prelude Data.Text> :t v1
v1 :: Text
pack関数 と unpack関数 でTextとStringを変換できる、Strict版とLazy版がある。
ByteString
バイナリ用途で利用、大量データ向き、高速、Strict版とLazy版がある、String型から利用する場合、 Data.ByteString.Char8 ライブラリを利用する。
Prelude> :m Data.ByteString.Char8
Prelude Data.ByteString.Char8> :t pack
pack :: String -> ByteString
Prelude Data.ByteString.Char8> let v1 = pack "あああ"
Prelude Data.ByteString.Char8> :t v1
v1 :: ByteString
Prelude Data.ByteString.Char8> :m +Data.ByteString
Prelude Data.ByteString.Char8 Data.ByteString> :t Data.ByteString.unpack v1
Data.ByteString.unpack v1 :: [GHC.Word.Word8]
OverloadedStrings拡張
リテラルを適切TextやByteStringへ変換してくれるGHC拡張、ファイルの先頭にかけば、 可能ならば pack や unpack を書かなくても変換してくれる。
{-# LANGUAGE OverloadedStrings #-}
Builder系ライブラリ
別のライブラリに Data.ByteString.Builder があり
Prelude> :m Data.ByteString.Builder
Prelude Data.ByteString.Builder> :t stringUtf8
stringUtf8 :: String -> Builder
Prelude Data.ByteString.Builder> toLazyByteString $ stringUtf8 "あああ"
"\227\129\130\227\129\130\227\129\130"
Unicode から UTF-8 へ変換し、それをバイト列で保存できるので、これを iconv に食わせて文字コード変換を行う。
Prelude > :m Data.ByteString.Builder
Prelude Data.ByteString.Builder> :m +Codec.Text.IConv
Prelude Data.ByteString.Builder Codec.Text.IConv> convert "UTF-8" "SHIFT_JIS" (toLazyByteString $ stringUtf8 "あああ")
"\130\160\130\160\130\160"
“\130\160\130\160\130\160” はShftJISにエンコードされた文字バイト。
サンプルコード
ShiftJISのファイルを読み込みText型へ変換する、ファイルをそのままByteString(ShiftJIS)で読み込み、Iconvの convert関数 で ShiftJIS から UTF-8 へ変換する。 その後、UTF-8から decodeUtf8関数 で Unicode へ変換し改行コードを処理する。
{-# LANGUAGE OverloadedStrings #-}
import System.IO
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Codec.Text.IConv as I
import qualified Data.ByteString.Lazy as L
main :: IO ()
main = do
bs <- L.hGetContents =<< openBinaryFile "sjis.txt" ReadMode
print $ T.replace "\r\n" "\n"
(T.decodeUtf8 $ L.toStrict (I.convert "SHIFT_JIS" "UTF-8" bs))
putStrLn "OK Read file"
途中、LazyにしたりStrictへ戻したりと面倒ではあります、以上備忘録です。
Posted on 2021-06-20 16:14:38