Scala 在parboiled2中以字符结尾的字符串,该字符串可以包含该字符

Scala 在parboiled2中以字符结尾的字符串,该字符串可以包含该字符,scala,peg,parboiled,parboiled2,Scala,Peg,Parboiled,Parboiled2,我在编写parboiled2解析器时遇到了一个棘手的问题,那就是我需要匹配一行的一部分,这是一个字符串,其结尾由:字符标记。这很简单,只是字符串可以包含:字符 目前,我得到了一个将字符串视为一组以冒号结尾的字符串并对其进行连接的方法,但这会消耗尾随:,我不希望使用尾随:,因为尾随:不是字符串本身的一部分 def address = rule { capture(oneOrMore(zeroOrMore(noneOf(":")) ~ ":")) } 我觉得我应该在这里的某个地方使用&(“:”),

我在编写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(端点(无,部分(80)),Seq())
  • bind localhost:80
    ->
    bind(端点(一些(“localhost”),一些(80)),Seq())
  • bind localhost
    ->
    bind(端点(一些(“localhost”),无),Seq())
  • bind:80 param1
    ->
    bind(端点(无,部分(80)),Seq(“param1”)
换句话说,如果有一个字符串,它需要在最后一个
之前终止,因为这是有端口的指示器。
端点
规则如下所示:

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

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

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

def noColons=规则{zeroOrMore(noneOf(“:”)}
def colonWithNext=规则{':'~&(noColons~':')}
def address=规则{capture(一个或多个(noColons).separatedBy(colonWithNext))~':'}
代码中的问题是~combinator的使用,因为像
A~B
这样的表达式只在A匹配,然后B匹配时才匹配,但是如果规则B是规则A的一部分,它在B处会不匹配。这里不涉及回溯,parboiled2解析器只回溯备选方案


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

您能否给出一个有效的“较长字符串”的示例,以及您希望从该字符串中获得什么(即:成功匹配)?@David我添加了一些上下文,同时尝试将问题相对隔离。实际情况比较复杂(,),但希望有足够的内容来理解这个问题。因此,您可以有一行
bind1:::80
,并希望输出
bind(端点(一些(“1:”),一些(80)),Seq()
?这是您的问题出现的一个好例子吗?是的,这是一个具体问题的好例子。很好,谢谢--我开始沿着这些思路取得一些进展,但是
capture
separatedBy
的组合是关键所在(我放弃了分隔符)。我也试着用一条规则来写,而把它分开会让事情更清楚。