如何在 attoparsec 中使用带有结尾字符的 sepBy?

How can I use sepBy with an ending character in attoparsec?

我正在尝试解析以下行:

ItemCount count@Int: You have purchased #{showInt count} #{plural count "item" "items"}

基本上我想得到:

  Message {
      key = "ItemCount",
      value = "You have purchased #{showInt count} #{plural count \"item\" \"items\"}.",
      parameters = [Parameter {name = "count", paramType = "Int"}]
      }

第一位 ItemCount count@Int: 可以是:

ItemCount:

ItemCount count@Int count2@Int:

所以参数可能出现零次或多次。我不确定在使用 sepBy 时如何检测 :。如果我使用 Parsec,我会使用 sepEndBy https://hackage.haskell.org/package/parsec-3.1.13.0/docs/Text-ParserCombinators-Parsec-Combinator.html#v:sepEndBy.

我正在寻找 sepBy,直到它看到 : 的字符。我想我可以先消耗所有东西直到 : 然后 运行 消耗字符串的 'inner' parse onn,但是处理所有失败案例(部分等)似乎很乏味,而且我认为一定有更好的方法。

这是我的代码:

import Control.Applicative
import Data.Attoparsec.Text
import Data.Text (Text)

data Parameter = Parameter { name :: Text, paramType :: Text } deriving (Eq, Show)
data Message = Message { key :: Text, value :: Text, parameters :: [Parameter] } deriving (Eq, Show)
data KeyAndParameters = KeyAndParameters Text [Parameter]

parseParameter :: Parser Parameter
parseParameter = do
  n <- takeWhile1 (notInClass "@")
  _ <- char '@'
  t <- takeWhile1 (const True)
  return $ Parameter { name = n, paramType = t }

parseKeyAndParameters :: Parser KeyAndParameters
parseKeyAndParameters = do
  keyV <- takeWhile1 (notInClass " :")
  params <- parseParameter `sepBy` (char ' ')
  return $ KeyAndParameters keyV params

我想我对 sepBy 的运作方式有了更好的理解。本质上,您不必考虑 'remaining' 文本,因为使用 attoparsec 时,您不必消耗所有输出直到结束(与 Parsec 不同)。

例如给定 1+2+3=6 作为输入和以下内容:

parseExample :: Parser ([Text], Text)
parseExample = do
  numbers <- takeWhile1 (notInClass "=+") `sepBy` char '+'
  skip (== '=')
  total <- takeWhile1 (const True)
  return $ (numbers, total)

将 return: ( [ "1" , "2" , "3" ] , "6")

skip (== '=') 之后,您可以自由选择任何方式解析剩余的输入。