2015-01-27 5 views
1

Я столкнулся с сложной проблемой написания парсинга parboiled2, который заключается в том, что мне нужно сопоставить часть строки, которая представляет собой строку, которая имеет свой конец отмечены знаком :. Это было бы достаточно просто, за исключением того, что строка может содержать символ :.Строка, заканчивающаяся символом в parboiled2, когда строка может содержать этот символ

На данный момент я получил это, который обрабатывает строку как группа строк двоеточия завершающих и concats их, но это потребляет концевую :, которые я не хочу в качестве задней : не является частью строки сам.

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

Другими словами, если есть строка, она должна быть завершена до окончательного :, так как это индикатор, что есть порт. endpoint правило выглядит следующим образом:

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

В конечном счете Matchable строки для конечной точки, заканчивающийся пробелом или в конце линии, поэтому один из вариантов были бы не только захватить, пока пространство, а затем разбора строка отдельно, но я надеялся сделать это в основном синтаксическом анализаторе.

+0

Можете ли вы привести пример действительной «более длинной строки» и что вы ожидаете получить от этой строки (т. Е. Успешных совпадений)? – David

+0

@David Я добавил некоторый контекст, пытаясь сохранить проблему относительно изолированной. Реальный случай является более сложным ([code] (https://github.com/gregbeech/haproxy-config/blob/master/src/main/scala/com/gregbeech/haproxy/ConfigParser.scala#L55), [ spec] (http://cbonte.github.io/haproxy-dconv/configuration-1.5.html#4.2-bind)), но мы надеемся, что этого должно быть достаточно, чтобы понять проблему. –

+0

Итак, у вас может быть строка 'bind 1 ::: 80', и вы хотите вывести' Bind (Endpoint (Some ("1 ::"), Some (80)), Seq()) '? Это хороший случай, когда возникает ваша проблема? – David

ответ

2

Я думаю, что следующее должно работать для описания проблемы:

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

Проблема с кодом было использование в ~ комбинатора, так как выражение, как A ~ B соответствует только если сначала матчей, а затем B, но он будет несовпадающим в B, если правило B является частью правила A. В этом нет никакого обратного отслеживания, паршированный анализатор 2 только возвращается для альтернатив.

Итак, в этом случае вы должны убедиться, что потребляете «:», только если за ним следуют другие.

+0

Отлично, спасибо. Я начал с этого места, но комбинация 'capture' и' separateBy' была трюком (я отбрасывал разделители). Также я пытался написать его в одном правиле, тогда как его разделение делает вещи намного яснее. –