2012-06-26 59 views
2

解析我很新的Haskell和我目前正在努力解決需要一些字符串分析的一個問題。我的輸入字符串包含逗號分隔的引號中的單詞列表。我想將這個單個字符串解析爲字符串的列表,作爲字符串。我應該從哪裏開始學習解析這樣的字符串?是否有一個partuclar模塊和/或功能會有幫助?字符串在Haskell

p.s.請不要發佈完整的解決方案。我只是要求一個指針開始的地方,所以我可以學習如何做到這一點。

+4

[SPLIT](http://hackage.haskell.org/package/split)很可能是有用的。或者你可以使用真正的解析器,如[parsec](http://hackage.haskell.org/package/parsec)。 –

+0

聽起來這些單詞是用逗號*和*引號分隔的? –

+0

@BenMillwood詞語被引號包圍,並用逗號分隔。 –

回答

5

由於String s僅僅是Haskell中的Char s的列表,因此Data.List將是一個很好的開始尋找的地方(爲了學習Haskell)。

對於更復雜的情況(逗號可能嵌套在引號中,例如應忽略),parsec(如丹尼爾提到的)將是更好的解決方案。另外,如果你想分析CSV文件,你可以試試Text.CSV,儘管我沒有嘗試過,所以我不能說它會有多大的幫助。

1

在具有爲那些誰碰巧就這個問題一個完整的答案的利益,Data.Text有一些很好的功能,以及。

1

任何東西使用秒差距即是「真正的工作」。

對於引入讀取https://therning.org/magnus/archives/tag/parsec

+0

此鏈接現在位於http://therning.org/magnus/posts/2007-05-27-289-adventures-in-parsing.html;請參閱https://wiki.haskell.org/Parsec Sec。 5.2系列中的其他鏈接和其他資源 –

3

下面就來進行一個特別厚臉皮方式:

parseCommaSepQuotedWords :: String -> [String] 
parseCommaSepQuotedWords s = read ("[" ++ s ++ "]") 

這可能會實現,但它是很脆弱的,很愚蠢。本質上你使用的是Haskell編寫字符串列表幾乎幾乎與你的方式相符的事實,因此內置的Read實例是幾乎你想要的東西。你可以使用reads更好的錯誤報告,但在現實中,你可能想要做完全是另一回事。

一般來說,parsec真的值得一看 - 這是一個喜悅使用,並且最初真正讓我興奮的事情之一是Haskell。但是如果你想要一個自己開發的解決方案,我經常使用case語句對spanbreak的結果編寫簡單的東西。假設您正在尋找輸入中的下一個分號。然後break (== ';') inp將返回(before, after),其中:

  • beforeinp到內容(不包括)第一個分號(或全部,如果都沒有)
  • after是字符串的其餘部分:
    • 如果after不爲空,第一個元素是一個分號
    • 無論什麼事情發生,before ++ after == inp

所以解析用分號分隔的語句列表,我可以這樣做:

parseStmts :: String -> Maybe [Stmt] 
parseStmts inp = case break (== ';') inp of 
    (before, _ : after) -> -- ... 
    --^before is the first statement 
    -- ^ignore the semicolon 
    --   ^after is the rest of the string 
    (_, []) -> -- inp doesn't contain any semicolons 
5

最強大的解決方案是一個解析器組合。 Haskell有這幾條,但是,我想起最重要的是:

  • parsec:一個很好的通用解析庫
  • attoparsec:秒差距的一個更快的版本,犧牲了錯誤信息的質量和其他一些功能進行額外的速度
  • uu-parsinglib:一個非常強大的解析庫

解析器組合的一大優點是,它是非常容易使用定義解析器do表示法(或Applicative風格,如果您願意)。

如果你只是想要一些快速和簡單的字符串處理功能,然後諮詢text庫(用於高性能字節編碼字符串),或Data.List(普通列表的編碼字符串),它提供了必要的功能來操縱字符串。

+0

當我是一個noob時,我無法制作uu-parsinglib的正面和反面。從那以後,我還沒有嘗試過,但我不完全稱它爲友好。 –

3

我終於決定推出我自己的解析函數,因爲這是一個很簡單的情況。我已經學到了很多關於Haskell的,因爲我第一次張貼了這個問題,並希望記錄我的解決方案在這裏:

split :: Char -> String -> [String] 
split _ "" = [] 
split c s = firstWord : (split c rest) 
    where firstWord = takeWhile (/=c) s 
      rest = drop (length firstWord + 1) s 

removeChar :: Char -> String -> String 
removeChar _ [] = [] 
removeChar ch (c:cs) 
    | c == ch = removeChar ch cs 
    | otherwise = c:(removeChar ch cs) 

main = do 
    handle <- openFile "input/names.txt" ReadMode 
    contents <- hGetContents handle 
    let names = sort (map (removeChar '"') (split ',' contents)) 
    print names 
    hClose handle