Haskell 如何使用Parsec解析一行?

Haskell 如何使用Parsec解析一行?,haskell,parsec,Haskell,Parsec,我正在使用解析库Parsec来解析一些文本。 我只需要分析行,这些行是由任意字符组成的字符串,当其位于字符串末尾时,以“\n”或eof结尾。 调用parseHS'时,我收到投诉,称Exception:Text.ParserCombinators.Parsec.Prim.many:combinator“many”应用于接受空字符串的解析器。 parseHS' :: String -> Either ParseError [String] parseHS' input = parse hsFi

我正在使用解析库Parsec来解析一些文本。 我只需要分析行,这些行是由任意字符组成的字符串,当其位于字符串末尾时,以“\n”或eof结尾。 调用
parseHS'
时,我收到投诉,称
Exception:Text.ParserCombinators.Parsec.Prim.many:combinator“many”应用于接受空字符串的解析器。

parseHS' :: String -> Either ParseError [String]
parseHS' input = parse hsFile' "(unknown)" input

hsFile' :: GenParser Char st [String]
hsFile' = do
    many1 line

line :: GenParser Char st String
line = do
    result <- many (noneOf "\n")
    optional newline
    return result
parseHS'::String->ParseError[String]
parseHS'input=parse hsFile'(未知)输入
hsFile'::GenParser Char st[字符串]
hsFile'=do
多线
line::GenParser Char st String
line=do

结果如果将
many
(或
many1
)应用于接受空字符串的解析器,则语法不明确。空字符串经常可以被任意识别,导致不同的解析树


在这种情况下,
line
接受空字符串,并且
many1
按照
many
实现,因此这会触发异常。在您的情况下,解决方案可能是确保
始终使用至少一个字符。

使用解析器来处理这一问题太过分了,因为您对行的内容没有限制。有一个库函数,
,它以相当少的麻烦实现了您的要求

例如:

lines "Hello there\neveryone,\nhere are some lines,"
> ["Hello there", "everyone,", "here are some lines,"]

如果行具有某种结构,则应首先编码该行,而不是尝试将字符串向上切碎-自下而上是编写递归下降解析器的最佳方法。

当然,如果只需要按行分割输入,则可以使用

Parsec中的sepEndBy
做你想做的事-将输入拆分成一个由给定分隔符分隔的已解析实体列表,可以选择以它或eof结尾

line
的语法允许解析器为任何输入生成一个永无止境的行流。这可以通过在外部对行作出关于换行的决定来解决:

hsFile' = do
        x <- line
        xs <- many $ do
                newline
                line
        eof
        return (x:xs)

line = many $ noneOf "\n"
hsFile'=do

这似乎是正确的,而且异常没有多大意义,因为
noneOf
不接受空字符串。你确定你的代码中没有很多行吗?谢谢你的回复@Tarmil。是的,我有一条比这高一层的1号线。仅此而已。答案更新为包含完整的代码示例