2012-06-26 74 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