Haskell: テキスト型の周辺

文字列関係で, よく必要になるモジュールを紹介。text-icu パッケージを使います。

# cabal install --dry-run --global text-icu

libicu-devel rpmパッケージを事前にインストールしておくこと。

正規化

Unicode を扱うときは正規化が欠かせない。ただのテキストは NFC, インデックスのように使うフィールドでは NFKC を適用することが多い。

Haskell
[RAW]
  1. {-# LANGUAGE OverloadedStrings #-}
  2. import Data.Text.ICU -- Data.Text.ICU.Normalize ではない
  3. import Data.Text.IO as DTIO
  4. main :: IO ()
  5. main = do
  6. DTIO.putStrLn $ normalize NFKD "㍍" -- 出力 = メートル
normalize :: NormalizationMode -> Text -> Text
正規化方法と文字列を引数に取り, 正規化する。NormalizationModeデータ型の値としては、次から選ぶ;
NFD 正規分解 (Canonical Decomposition)
NFKD 互換分解 (Compatibility Decomposition)
NFC 正規分解 + 正規合成 (Canonical Composition)
NFKC 互換分解 + 正規合成

文字コード変換

非Unicode 文字コードとの相互変換。

まず、シフトJISで、次のファイルを用意する。

sjis.txt

このファイルはShift_JIS①②km㈱
涖涬淏淸淲淼渹湜渧渼

変換するコード. Converterデータ型を使う。

Haskell
[RAW]
  1. import Data.Text.ICU.Convert
  2. import Data.Text.IO as DTIO
  3. import Data.ByteString as DBS
  4. main :: IO ()
  5. main = do
  6. conv <- open "MS932" Nothing
  7. Prelude.putStrLn $ show conv
  8. bs <- DBS.readFile "sjis.txt"
  9. DTIO.putStrLn $ toUnicode conv bs

シフトJISは, "ibm-943_P15A-2003", "Windows-31J" または "MS932" のいずれかを指定する。どれでも同じ。"cp932" は異なる変換表のことかあり、避けるのが無難。

open :: String -> Maybe Bool -> IO Converter
文字コードを指定する。コンバータを生成する。

使える文字コードとその別名については, Converter Explorer

toUnicode :: Converter -> ByteString -> Text
バイト列を文字列に変換する。

実行結果:

Converter "ibm-943_P15A-2003"
このファイルはShift_JIS①②km㈱
涖涬淏淸淲淼渹湜渧渼

正規表現

Haskell には, パーサコンビネータ parsec パッケージがあり、標準インストールされる。これがあれば、正規表現の出番があまりない、か。

正規表現は, regex-compat パッケージのText.Regexモジュールもある。ただし, String を使っている。

text-icu パッケージの Data.Text.ICU.Regexモジュールが Text を使う。

Haskell
[RAW]
  1. {-# LANGUAGE OverloadedStrings #-}
  2. import Data.Text
  3. import Data.Text.IO as DTIO
  4. import Data.Text.ICU as DTICU -- Data.Text.ICU.Regex ではない
  5. pat :: Text
  6. pat = "(ふが)+ほ"
  7. main :: IO ()
  8. main = do
  9. case (DTICU.find (regex [] pat) "ほげふがふがほげ") of
  10. Just x -> Prelude.putStrLn $ show x
  11. Nothing -> DTIO.putStrLn "not found."

実行結果

Match ["\12405\12364\12405\12364\12411","\12405\12364"]
regex :: [MatchOption] -> Text -> Regex
Regexオブジェクトを生成する。
find :: Regex -> Text -> Maybe Match
パタンにマッチさせる。