Слово петрушка до настоящего момента

Я только начинаю с рубина и петрушки, так что это может быть очевидно для других (надеюсь).

Я хочу получить все слова до разделителя (^), не потребляя его

Следующее правило работает (но использует разделитель) с результатом {:wrd=>"otherthings"@0, :delim=>"^"@11}

require 'parslet'    
class Mini < Parslet::Parser
      rule(:word) { match('[a-zA-Z]').repeat}
      rule(:delimeter) { str('^') }
      rule(:othercontent) { word.as(:wrd) >> delimeter.as(:delim) }
      root(:othercontent)
end
puts Mini.new.parse("otherthings^")

Я пытался использовать "подарок",

require 'parslet' 
class Mini < Parslet::Parser
  rule(:word) { match('[a-zA-Z]').repeat}
  rule(:delimeter) { str('^') }
  rule(:othercontent) { word.as(:wrd) >> delimeter.present? }
  root(:othercontent)
end
puts Mini.new.parse("otherthings^")

но это бросает исключение:

Failed to match sequence (wrd:WORD &DELIMETER) at line 1 char 12. (Parslet::ParseFailed)

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

Я использую parslet 1.5.0.

Спасибо за вашу помощь!

1 ответ

Решение

TL;DR; Если вам небезразлично, что находится перед "^", вы должны сначала разобрать это.

--- длинный ответ ---

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

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

Если вы действительно хотите просто использовать весь текст перед разделителем, вы можете сделать что-то вроде этого...

Скажем, я собирался разобрать список разделенных '^' вещей.

Я мог бы иметь следующие правила

rule(:thing) { (str("^").absent? >> any).repeat(1) }  # anything that's not a ^
rule(:list)  { thing >> ( str("^") >> thing).repeat(0) } #^ separated list of things

Это будет работать следующим образом

parse("thing1^thing2") #=> "thing1^thing2"
parse("thing1") #=> "thing1"
parse("thing1^") #=> ERROR ... nothing after the ^ there should be a 'thing'

Это будет означать list будет соответствовать строке, которая не заканчивается или начинается с '^'. Однако, чтобы быть полезным, мне нужно извлечь биты, являющиеся значениями, с ключевым словом "as"

rule(:thing) { (str("^").absent? >> any).repeat(1).as(:thing) }
rule(:list)  { thing >> ( str("^") >> thing).repeat(0) }

Теперь когда list соответствует строке Я получаю массив хэшей "вещей".

parse("thing1^thing2") #=> [ {:thing=>"thing1"@0} , {:thing=>"thing2"@7} ] 

В действительности, однако, вам, вероятно, все равно, что такое "вещь"... не просто что-то пойдет туда

В этом случае... вы должны начать с определения этих правил... потому что вы не хотите использовать синтаксический анализатор для разделения на "^", а затем повторно проанализируйте строки, чтобы выяснить, из чего они сделаны.

Например:

parse("6 + 4 ^ 2") 
 # => [ {:thing=>"6 + 4 "@0}, {:thing=>" 2"@7} ]

И я, вероятно, хочу игнорировать white_space вокруг "вещи", и я, вероятно, хочу иметь дело с 6 + и 4 все по отдельности. Когда я сделаю это, мне придется выбросить мое правило "все, что не является" ^ "".

Другие вопросы по тегам