以下代码输出Right ["1<!>2<!>3"]
,但我需要Right ["1", "2", "3"]
。
import Text.ParserCombinators.Parsec
response = contents :: CharParser () [String]
where
contents = sepBy content contentDelimiter
contentDelimiter = string "<!>"
content = many anyChar
main = do
putStrLn $ show $ parse response "Response" "1<!>2<!>3"
我认为这里的问题是content
解析器在sepBy
测试分隔符之前消耗所有输入。所以,我的问题是:
我的假设是否正确?如果没有,我犯了什么错误?
您会为这样的问题推荐什么解决方案? (使用Parsec)
* content
必须匹配任何不包含分隔符的字符串。 1<!>2<!>3
只是一个例子,它可以是dslkf\n><!>dsf<!>3
或其他
答案 0 :(得分:8)
对于您的第一个示例,您将替换
content = many anyChar
与
content = many digit
这样内容的解析器就不会错误地匹配分隔符。
也许您希望匹配的不仅仅是数字,但即便如此,我建议您仔细考虑{em> 在<!>
之间有效,并编写一个解析器。
<强>为什么吗
一旦你有一个非常好的内容解析器,你的响应定义将是完美的。这样,您的内容可以包含mystring = "hello<!>mum"
,而不会被顶级解析器切断 - 低级stringLiteral
解析器会占用整个"hello<!>mum"
,顶级解析器将永远不会看到{{1}正确无误地包含在其中。
<强>通常,... 强>
在大多数解析情况下,最好清楚地了解内容中允许的内容,并仅解析内容,原因有三:
可重用性很重要。目前,如果您使用的解析器只是在<!>
上拆分并吃掉其他所有内容,那么它肯定会占用整个输入,并且您将无法再进行解析。
<强>自下而上强>
您的解析器应该从头开始工作 - 您在评论中将此描述为“将解析器从特定堆叠到一般”。
最容易按顺序编写它们以便于测试,因此首先在<!>
之前stringChar
之前写stringLiteral
然后member
匹配array
之前的object
} json
之前的content
然后response
。你可以让他们一路上递归地互相呼叫。然后,您可以使用parseTest
来测试每个小家伙;在ghci中键入parseTest response "1<!>2<!>3"
比重写main和编译更快。
热门向下吗
自上而下编写解析器并没有错,只是更难。你可以写
response = many $ content `sepBy` contentSeparator
content = json <|> somethingElse
json = object <|> array
array = ...
但在你写完最小的解析器之前,没有什么是可测试的。
答案 1 :(得分:0)
如果不是'&lt;',我建议使用noneOf
的解决方案和'!',也不是'&gt;'是您内容的一部分。
import Text.ParserCombinators.Parsec
response = contents :: CharParser () [String]
where
contents = sepBy content contentDelimiter
contentDelimiter = string "<!>"
content = many (noneOf ['<','!','>'])
main = print $ parse response "Response" "1<!>2<!>3"