我遇到了一个写一个parboiled2解析器的棘手问题,我需要匹配一行的一部分,这是一个字符串,其末尾标有:
个字符。这很容易,除了字符串可以包含 :
字符。
目前我有这个将字符串视为一组以冒号结尾的字符串并将它们连接起来,但这会消耗尾随的:
,我不想将其作为尾随:
}不是字符串本身的一部分。
def address = rule { capture(oneOrMore(zeroOrMore(noneOf(":")) ~ ":")) }
我觉得我应该在这里的某个地方使用&(":")
,但是在匹配插页式:
字符时,我很难努力工作。
示例成功匹配(作为较长字符串的一部分):
localhost:
- > localhost
1:::
- > 1::
:::
- > ::
错配:
:
任何建议都会受到欢迎,即使它是“你不能这样做”所以我可以停止绞尽脑汁。
此上下文是解析HAProxy配置文件中的bind
设置。给出以下(简化)案例类的有效字符串的一些示例是:
case class Bind(endpoint: Endpoint, params: Seq[String])
case class Endpoint(address: Option[String], port: Option[Int])
bind :80
- > Bind(Endpoint(None, Some(80)), Seq())
bind localhost:80
- > Bind(Endpoint(Some("localhost"), Some(80)), Seq())
bind localhost
- > Bind(Endpoint(Some("localhost"), None), Seq())
bind :80 param1
- > Bind(Endpoint(None, Some(80)), Seq("param1")))
换句话说,如果有一个字符串,则需要在最终:
之前终止,因为这是指示有一个端口。 endpoint
规则如下所示:
def endpoint = rule { optional(address) ~ optional(':' ~ int) ~> Endpoint }
最终端点的匹配字符串由空格或行的末尾终止,因此一个选项是捕获直到空格然后分别解析字符串,但我希望在主解析器。
答案 0 :(得分:2)
我认为以下内容适用于您的问题描述:
def noColons = rule { zeroOrMore(noneOf(":")) }
def colonWithNext = rule { ':' ~ &(noColons ~ ':') }
def address = rule { capture(oneOrMore(noColons).separatedBy(colonWithNext)) ~ ':' }
你的代码的问题是〜组合子的使用,因为像A ~ B
这样的表达式只匹配起初A匹配然后B匹配,但如果规则B ,则它在B处不匹配规则A的一部分。这里没有涉及回溯,parboiled2解析器只回溯替代。
所以,在这种情况下,你必须确保只有在跟随它的另一个人时才使用':'。