1

我在编写 parboiled2 解析器时遇到了一个棘手的问题,即我需要匹配行的一部分,该行是一个字符串,其结尾由一个:字符标记。这很容易,除了字符串可以包含字符:

目前我有这个将字符串视为一组以冒号结尾的字符串并将它们连接起来,但这会消耗:我不想要的尾随,因为尾随:不是字符串本身的一部分。

def address = rule { capture(oneOrMore(zeroOrMore(noneOf(":")) ~ ":")) }

我觉得我应该&(":")在这里的某个地方使用,但我在匹配插页式:字符的同时努力工作。

成功匹配示例(作为较长字符串的一部分):

  • localhost:->localhost
  • 1:::->1::
  • :::->::

不匹配:

  • :

任何建议都会受到欢迎,即使它是“你不能这样做”,所以我可以停止绞尽脑汁。


上下文是解析bindHAProxy 配置文件中的设置。给定以下(简化的)案例类的一些有效字符串示例是:

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")))

换句话说,如果有一个字符串,它需要在 final 之前终止,:因为这表明存在端口。endpoint规则如下所示:

def endpoint = rule { optional(address) ~ optional(':' ~ int) ~> Endpoint }

最终,端点的可匹配字符串由空格或行尾终止,因此一种选择是只捕获空格,然后单独解析字符串,但我希望在主解析器中完成。

4

1 回答 1

2

我认为以下内容应该适用于您的问题描述:

def noColons = rule { zeroOrMore(noneOf(":")) }
def colonWithNext = rule { ':' ~ &(noColons ~ ':') }
def address = rule { capture(oneOrMore(noColons).separatedBy(colonWithNext)) ~ ':' }

您的代码的问题是使用了 ~ 组合器,因为A ~ B只有在首先 A 匹配然后 B 匹配时才匹配的表达式,但如果规则 B规则 A 的一部分,它将在 B 处不匹配。这里不涉及回溯, parboiled2 解析器只回溯替代方案。

因此,在这种情况下,您必须确保仅在后面有另一个时才使用“:”。

于 2015-01-28T07:18:29.580 回答