Haskellによる日本語テキスト処理(Windows上で)

Haskellでテキストを処理しようとするとき,このように書きたくなるであろう:

-- テキストをHTMLに変換する
module Main where

import System.Environment(getArgs)

htmlEncode :: String -> String
htmlEncode [] = []
htmlEncode (c:cs) = (f c) ++ htmlEncode cs
  where
    f :: Char -> String
    f '' = ">"
    f '&' = "&"
    f '"' = """
    f a = [a]

main :: IO ()
main = do
  [inputF, outputF] <- getArgs  :: IO [String]
  inputText <- readFile inputF
  let outText = unlines $ htmlEncode  (lines inputText) :: String
  writeFile outputF outText

上のプログラムをWindows上で日本語(utf-8)が含まれたテキストを処理することを考える:
$ stack exec converter -- app/Main.hs main.htm
すると「 hGetContents: invalid argument (invalid byte sequence)」というようなことを言われてうまく処理できなかった.テキストがShift-JISとして読まれているためにこうなるらしい(よく理解できていない).

ロケールを変更すると良いらしいのだが方法がよくわからなかったので次のようにプログラム側で対処した:

-- テキストをHTMLに変換する
module Main where

import System.Environment(getArgs)
import System.IO (IOMode (..), hGetContents, hSetEncoding, openFile, hPutStr, hClose)
import GHC.IO.Encoding (utf8)

htmlEncode :: String -> String
htmlEncode [] = []
htmlEncode (c:cs) = (f c) ++ htmlEncode cs
  where
    f :: Char -> String
    f '' = ">"
    f '&' = "&"
    f '"' = """
    f a = [a]

main :: IO ()
main = do
  [inputF, outputF] <- getArgs  :: IO [String]
  handle <- openFile inputF ReadMode
  hSetEncoding handle utf8
  inputText <- hGetContents handle :: IO String
  let outText = unlines $ htmlEncode  (lines inputText) :: String
  ohandle <- openFile outputF WriteMode
  hSetEncoding ohandle utf8
  hPutStr ohandle outText
  hClose ohandle

optparse-genericを使ったバージョンは:

-- テキストをHTMLに変換する
{-# OPTIONS_GHC -Wall -fwarn-tabs #-}
{-# LANGUAGE DataKinds            #-}
{-# LANGUAGE DeriveGeneric        #-}
{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE OverloadedStrings    #-}
{-# LANGUAGE StandaloneDeriving   #-}
{-# LANGUAGE TypeOperators        #-}

module Main where

import System.IO (IOMode (..), hGetContents, hSetEncoding, openFile, hPutStr, hClose)
import GHC.IO.Encoding (utf8)
import Options.Generic --stack install optparse-generic

data OptionInput  w = OptionInput
  { rawtext :: w ::: String           "raw text file to be transformed"
  , htmlout :: w ::: String           "HTML output file"
  } deriving (Generic)

instance ParseRecord (OptionInput Wrapped)
deriving instance Show (OptionInput Unwrapped)

htmlEncode :: String -> String
htmlEncode [] = []
htmlEncode (c:cs) = (f c) ++ htmlEncode cs
  where
    f :: Char -> String
    f '' = ">"
    f '&' = "&"
    f '"' = """
    f a = [a]

main :: IO ()
main = do
  x  html"
  let
    inputF = rawtext x :: String
    outputF = htmlout x :: String
  handle <- openFile inputF ReadMode
  hSetEncoding handle utf8
  inputText <- hGetContents handle :: IO String
  let outText = unlines $ htmlEncode  (lines inputText) :: String
  ohandle <- openFile outputF WriteMode
  hSetEncoding ohandle utf8
  hPutStr ohandle outText
  hClose ohandle

参考にした記事:WindowsでHaskellを扱う時によく遭遇するエラーと対処法

広告
コメントする

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。