2

解析ライブラリ Parsec を使用してテキストを解析しています。文字列の最後にある場合は、「\ n」またはeofで終わる任意の文字の文字列である行を解析するだけです。電話するparseHS'と、という苦情が来Exception: Text.ParserCombinators.Parsec.Prim.many: combinator 'many' is applied to a parser that accepts an empty string.ます。

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

どうすればこれを正しく達成できるでしょうか?

4

3 に答える 3

6

(とりわけ) 空の文字列を受け入れるパーサーに適用many(または) すると、あいまいな文法になります。many1空の文字列は任意の頻度で認識される可能性があり、その結果、異なる解析ツリーが生成されます。

この場合、lineは空の文字列を受け入れ、 のmany1観点から実装されているmanyため、これにより例外がトリガーされます。あなたの状況での解決策は、おそらくline常に少なくとも 1 文字を消費するようにすることです。

于 2013-09-18T16:30:35.093 に答える
6

もちろん、入力を行ごとに分割するだけでよい場合は、 を使用できますlines

sepEndByin Parsec はあなたが望むことをします - 入力を特定のセパレーターで区切られた解析済みエンティティのリストに分割し、オプションでそれまたは eof で終わります。

for の文法lineにより、パーサーは入力に対して終わりのない行のストリームを生成できます。これは、行の外部で改行に関する決定を下すことで解決できます。

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

line = many $ noneOf "\n"

ファイルが改行で終わる場合、これは最後に空の行を生成します。

于 2013-09-19T07:30:06.823 に答える
2

行の内容に制限がないため、これにパーサーを使用するのはやり過ぎです。linesあなたが求めていることをかなり手間をかけずに達成するライブラリ関数があります。

例:

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

行に何らかの構造がある場合は、文字列を切り刻むのではなく、最初にそれをコーディングする必要があります。再帰降下パーサーを作成するには、ボトムアップが最善の方法です。

于 2013-09-18T21:58:48.053 に答える