2014-10-22 68 views
4

我想解析一個製表符分隔的文件,在Haskell中使用木薯/Data.Csv。但是,如果CSV文件中存在「奇怪」(Unicode)字符,我會遇到問題。那麼我會得到一個parse error (endOfInput)解析Haskell中的CSV/TSV文件 - Unicode字符

根據命令行工具「file」,我的文件有一個「UTF-8 Unicode文本」解碼。我的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 

我試着用decodingUtf8' ,預處理(過濾)從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 ????!!!! 

問題字符是與•(在我完整的文件,還有更多的類似字符)。我能做些什麼,以便木薯/ Data.Csv能夠正確讀取我的文件?

編輯: 我創建了以下預處理器與木薯(見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 
+1

標籤分隔符(而不是字段本身內部的空格)在哪裏?從上面粘貼的示例數據中不容易看到?您可以使用例如一個字符串''字符串來顯示標籤在哪裏?我假設最後一個字段以「RT USE ...」開頭。 – tibbe 2014-10-22 06:42:26

+0

對不起,我沒有意識到標籤被轉換爲空格: a \ t- \ t- \ t- \ tRT使用「Kenny」•Hahahahahahahahaha。 #Emmen #Brandstapel \ na \ t- \ t- \ t- \ tUhm .. wat dan ook ???? !!!! – Pold 2014-10-22 09:51:36

回答

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\"") 

(請注意,我必須確保在字面Text型相當的使用encodeUtf8而不僅僅是直接使用ByteString文字。用於ByteStringIsString實例用於將文字轉換爲ByteString,截斷每個Unicode代碼點。)

+1

謝謝,這很好,Unicode字符不會導致錯誤了。但是,對於使用雙引號轉義的字段,我需要解決這個問題。爲了解決這個問題,我需要用木薯解碼我的CSV。但用木薯解碼會導致解析錯誤,因爲字段還沒有被轉義。我有幾個CSV文件和每個數千條,因此手動轉義它們不是一種選擇。有沒有辦法用木薯做到這一點(我想避免用另一種工具預處理文件)? – Pold 2014-10-24 23:07:46