1

私は、parboiled2 パーサーを作成する際に厄介な問題に遭遇しました。つまり、末尾が文字でマークされた文字列である行の一部と一致させる必要があるということです:。文字列に文字を含めることができることを除けば、これは簡単:です。

現時点では、文字列をコロンで終わる文字列のグループとして扱い、それらを連結するこれがありますが、これは、末尾が文字列自体の一部ではないため:、望ましくない末尾を消費します。:

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

ここのどこかで使用する必要があるように感じますが、インタースティシャル文字&(":")を一致させながらそれを処理するのに苦労しています.:

成功した一致の例 (長い文字列の一部として):

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

不一致:

  • :

「あなたにはできない」ということでも、どんな提案でも大歓迎です。


これのコンテキストはbind、HAProxy 構成ファイルの設定を解析することです。次の (簡略化された) ケース クラスが与えられた場合の有効な文字列の例を次に示します。

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 }

最終的に、エンドポイントの一致可能な文字列はスペースまたは行末で終了するため、1 つのオプションはスペースまでキャプチャしてから文字列を個別に解析することですが、メイン パーサー内で実行することを望んでいました。

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 に答える