以 parboiled2 中的字符结尾的字符串,当字符串可以包含该字符时
String ending with character in parboiled2, when the string can contain that character
我在编写 parboiled2 解析器时遇到了一个棘手的问题,即我需要匹配一行的一部分,该行是一个字符串,其结尾标有 :
字符。这很容易,除了字符串可以 包含 :
字符。
目前我有这个将字符串视为一组以冒号结尾的字符串并将它们连接起来,但这消耗了尾随 :
,我不希望它作为尾随 :
不是字符串本身的一部分。
def address = rule { capture(oneOrMore(zeroOrMore(noneOf(":")) ~ ":")) }
我觉得我应该在这里的某个地方使用 &(":")
,但我在匹配插页式 :
字符时正在努力工作。
成功匹配示例(作为较长字符串的一部分):
localhost:
-> localhost
1:::
-> 1::
:::
-> ::
不匹配:
:
欢迎任何建议,即使是 "you can't do this" 这样我就可以停止绞尽脑汁了。
此上下文正在解析 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 }
最终,端点的可匹配字符串以 space 或行尾终止,因此一种选择是只捕获到 space,然后分别解析字符串, 但我希望在主解析器中完成它。
我认为以下内容应该适用于您的问题描述:
def noColons = rule { zeroOrMore(noneOf(":")) }
def colonWithNext = rule { ':' ~ &(noColons ~ ':') }
def address = rule { capture(oneOrMore(noColons).separatedBy(colonWithNext)) ~ ':' }
您的代码的问题在于使用了 ~ 组合器,因为像 A ~ B
这样的表达式仅在首先 A 匹配然后 B 匹配时才匹配,但如果规则 B 是规则A的一部分。这里不涉及回溯,parboiled2解析器只回溯备选方案。
因此,在这种情况下,您必须确保仅在后面有另一个时才使用“:”。
我在编写 parboiled2 解析器时遇到了一个棘手的问题,即我需要匹配一行的一部分,该行是一个字符串,其结尾标有 :
字符。这很容易,除了字符串可以 包含 :
字符。
目前我有这个将字符串视为一组以冒号结尾的字符串并将它们连接起来,但这消耗了尾随 :
,我不希望它作为尾随 :
不是字符串本身的一部分。
def address = rule { capture(oneOrMore(zeroOrMore(noneOf(":")) ~ ":")) }
我觉得我应该在这里的某个地方使用 &(":")
,但我在匹配插页式 :
字符时正在努力工作。
成功匹配示例(作为较长字符串的一部分):
localhost:
->localhost
1:::
->1::
:::
->::
不匹配:
:
欢迎任何建议,即使是 "you can't do this" 这样我就可以停止绞尽脑汁了。
此上下文正在解析 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 }
最终,端点的可匹配字符串以 space 或行尾终止,因此一种选择是只捕获到 space,然后分别解析字符串, 但我希望在主解析器中完成它。
我认为以下内容应该适用于您的问题描述:
def noColons = rule { zeroOrMore(noneOf(":")) }
def colonWithNext = rule { ':' ~ &(noColons ~ ':') }
def address = rule { capture(oneOrMore(noColons).separatedBy(colonWithNext)) ~ ':' }
您的代码的问题在于使用了 ~ 组合器,因为像 A ~ B
这样的表达式仅在首先 A 匹配然后 B 匹配时才匹配,但如果规则 B 是规则A的一部分。这里不涉及回溯,parboiled2解析器只回溯备选方案。
因此,在这种情况下,您必须确保仅在后面有另一个时才使用“:”。