如何在 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 (== '=')
之后,您可以自由选择任何方式解析剩余的输入。
我正在尝试解析以下行:
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 (== '=')
之后,您可以自由选择任何方式解析剩余的输入。