我正在尝试使用Haskell中的cassava / Data.Csv解析制表符分隔的文件。但是,如果我的CSV文件中存在“奇怪的”(Unicode)字符,则会出现问题。我会得到一个parse error (endOfInput)
。
根据命令行工具“file”,我的文件有一个“UTF-8 Unicode text”解码。我的Haskell代码如下所示:
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString as C
import qualified System.IO.UTF8 as U
import qualified Data.ByteString.UTF8 as UB
import qualified Data.ByteString.Lazy.Char8 as DL
import qualified Codec.Binary.UTF8.String as US
import qualified Data.Text.Lazy.Encoding as EL
import qualified Data.ByteString.Lazy as L
import Data.Text.Encoding as E
-- Handle CSV / TSV files with ...
import Data.Csv
import qualified Data.Vector as V
import Data.Char -- ord
csvFile :: FilePath
csvFile = "myFile.txt"
-- Set delimiter to \t (tabulator)
myOptions = defaultDecodeOptions {
decDelimiter = fromIntegral (ord '\t')
}
main :: IO ()
main = do
csvData <- L.readFile csvFile
case EL.decodeUtf8' csvData of
Left err -> print err
Right dat ->
case decodeWith myOptions NoHeader $ EL.encodeUtf8 dat of
Left err -> putStrLn err
Right v -> V.forM_ v $ \ (category :: String ,
user :: String ,
date :: String,
time :: String,
message :: String) -> do
print message
我尝试使用decodeUtf8',使用来自Data.Char的谓词预处理(过滤)输入等等。但是,endOfFile错误仍然存在。
我的CSV文件如下所示:
a - - - RT USE " Kenny" • Hahahahahahahahaha. #Emmen #Brandstapel
a - - - Uhm .. wat dan ook ????!!!!
或更确切地说:
a\t-\t-\t-\tRT USE " Kenny" • Hahahahahahahahaha. #Emmen #Brandstapel
a\t-\t-\t-\tUhm .. wat dan ook ????!!!!
问题字符是和•(在我的完整文件中,还有更多相似的字符)。我能做些什么,以便cassava / Data.Csv可以正确读取我的文件?
修改 我在用cassava解码之前创建了以下预处理器来转义我的文本(参见tibbe的回答)。可能有更好的可能性,但到目前为止,工作正常!
import qualified Data.Text as T
preprocess :: T.Text -> T.Text
preprocess txt = cons '\"' $ T.snoc escaped '\"'
where escaped = T.concatMap escaper txt
escaper :: Char -> T.Text
escaper c
| c == '\t' = "\"\t\""
| c == '\n' = "\"\n\""
| c == '\"' = "\"\""
| otherwise = T.singleton c
答案 0 :(得分:4)
根据木薯文件:
非转义字段可能包含除双引号,逗号,回车符和换行符之外的任何字符。
转义字段可能包含任何字符(但需要转义双引号)。
由于第一个记录中的最后一个字段包含双引号,因此需要使用双引号对字段进行转义,并且需要对任何双引号进行转义,如下所示:
a - - - "RT USE "" Kenny"" • Hahahahahahahahaha. #Emmen #Brandstapel"
此代码适用于我:
import Data.ByteString.Lazy
import Data.Char
import Data.Csv
import Data.Text.Encoding
import Data.Vector
test :: Either String (Vector (String, String, String, String, String))
test = decodeWith
defaultDecodeOptions {decDelimiter = fromIntegral $ ord '\t' }
NoHeader
(fromStrict $ encodeUtf8 "a\t-\t-\t-\t\"RT USE \"\" Kenny\"\" • Hahahahahahahahaha. #Emmen #Brandstapel\"")
(请注意,我必须确保在encodeUtf8
字面上使用Text
,而不是直接使用ByteString
字面值。IsString
实例{ {1}} s,用于将文字转换为ByteString
,用于截断每个Unicode代码点。)