Haskellの文字について

Tech > 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

はじめまして

お茶の国静岡で、焼酎のお茶割なんか罰当たりで飲んだことはありません、常に一番搾りを嗜む静岡極東のBBQerです、最近まわりのエンジニアの方々がお料理を上手にやっている姿を恨めしそうに横目に見ながら、軟骨ピリ辛チクワを食べています、みなさんよろしく。

Posted

Amazon

tags

家系 日本酒池 広井酒店 やがら やっぱた 刺身 丸干し 鯵 東京マラソン fpm php82 servant thread spawn Rust Oracle Linux 8 microcode firmware linux openzfs zfs gitea 麒麟 真野鶴 金鶴 日本酒 docker oracle pod podman cli virtualbox VirtualBox epub mobi calibre mask lens ワンライナー php 海 redmine Linux Oracle Map OMap omap map 夏 BBQ カテゴリ管理 カテゴリ timestamp date oracle database string 麦焼酎 ダービー process 磨き蒸留 広井酒店、日本酒 芋焼酎 酒 焼酎 ゆるキャン 広井酒店、日本酒池 spring framework java persistent spring session session spring hdbc-odbc persistent-odbc odbc day utctime スィート レマンの森 elm初期化 elm バイク xlr80 esqueleto database xl2tpd strongswan vpn l2tp ipsec 正月 ゲーム grub nginx systemctl portage 豚骨 圧力鍋 yesod-auth-hashdb yesod-auth