1

我想将一些非常简单的文本解析 "abcxyzzzz\nhello\n"["abcxyzzz", "hello"] :: String.

不寻找更简单的函数来执行此操作(例如words),因为我需要解析更复杂的东西,而我只是在这里奠定基础。

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}

module RgParse where

import Data.Text (Text)
import Text.Megaparsec
import Text.Megaparsec.Char


data SimpleData = SimpleData String deriving (Eq, Show, Ord)
data SimpleData' = SimpleData' [String] deriving (Eq, Show, Ord)

instance ShowErrorComponent SimpleData where
  showErrorComponent = show

instance ShowErrorComponent String where
  showErrorComponent = show



simple :: Parsec String Text SimpleData
simple = do
  x <- many (noneOf (Just '\n'))
  pure $ SimpleData x

simple' :: Parsec String Text SimpleData'
simple' = do
  x <- many (many (noneOf (Just '\n')))
  pure $ SimpleData' x

example2 :: Text
example2 = "abcxyzzzz\nhello\n"

main :: IO ()
main = do
  print "Simple:"
  case parse simple "<stdin>" example2 of
    Left bundle -> putStr (errorBundlePretty bundle)
    Right result -> print result
  print "Simple':"
  case parse simple' "<stdin>" example2 of
    Left bundle -> putStr (errorBundlePretty bundle)
    Right result -> print result
  print "done.."

不幸的是,上面的内容在输入时遇到了无限循环/空间泄漏,simple'因为它输出以下内容:

Hello, Haskell!
[]
"Simple:"
SimpleData "abcxyzzzz"
"Simple':"

使用 megaparsec-7.0.5(不是最新的 9.xx)。

是否有更简单的方法来获得多行?

4

1 回答 1

2

仅适用many于消耗至少一个令牌(此处为一个Char)或失败的解析器。那是因为many通过运行它的参数直到它失败。many x可能会消耗零令牌,因此many (many x)打破了这个要求。

请注意,一行应该至少包含一个终止换行符。这允许满足该要求。

oneline :: Parsec String Text String
oneline = many (noneOf (Just '\n')) <* single '\n'

manylines :: Parsec String Text [String]
manylines = many oneline

simple :: Parsec String Text SimpleData
simple = do
  x <- oneline
  pure $ SimpleData x

simple' :: Parsec String Text SimpleData'
simple' = do
  x <- manylines
  pure $ SimpleData' x

一个更宽松的要求many p是,任何重复p必须在有限次数的迭代后失败(这里p = many x永远不会失败),因此p在某些步骤中可能不消耗任何内容,但它必须是有状态的,以便在一些重复之后它最终消耗一些东西或失败。但在实践中,上述近似值是一个非常好的经验法则。

于 2021-12-20T19:00:57.673 回答