Eu estou apenas começando com ruby e parslet, então isso pode ser óbvio para os outros (espero).
Eu estou querendo obter todas as palavras até um delimitador (^) sem consumi-lo
A regra a seguir funciona (mas consome o delimitador) com um resultado de {:wrd=>"otherthings"@0, :delim=>"^"@11}
require 'parslet' class Mini > delimeter.as(:delim) } root(:othercontent) end puts Mini.new.parse("otherthings^")
Eu estava tentando usar o ‘presente’,
require 'parslet' class Mini > delimeter.present? } root(:othercontent) end puts Mini.new.parse("otherthings^")
mas isso lança uma exceção:
Failed to match sequence (wrd:WORD &DELIMETER) at line 1 char 12. (Parslet::ParseFailed)
Posteriormente, vou querer inspecionar a palavra à direita do delimitador para criar uma gramática mais complexa, e é por isso que não quero consumir o delimitador.
Estou usando o parslet 1.5.0.
Obrigado pela ajuda!
TL; DR; Se você se importa com o que é antes do “^” você deve analisar isso primeiro.
— mais tempo de resposta —
Um analisador sempre consumirá todo o texto. Se não puder consumir tudo, o documento não será totalmente descrito pela gramática. Em vez de pensar nisso como algo que executa “divisões” em seu texto … em vez disso, pense nele como uma máquina de estado inteligente que consome um stream de texto.
Então … como sua gramática completa precisa consumir todo o documento … ao desenvolver seu analisador, você não pode fazer isso para analisar alguma parte e deixar o resto. Você quer transformar seu documento em uma tree para que você possa manipulá-lo de forma definitiva.
Se você realmente queria apenas consumir todo o texto antes de um delimitador, então você poderia fazer algo assim …
Digamos que eu fosse analisar uma lista separada de coisas.
Eu poderia ter as seguintes regras
rule(:thing) { (str("^").absent? >> any).repeat(1) } # anything that's not a ^ rule(:list) { thing >> ( str("^") >> thing).repeat(0) } #^ separated list of things
Isso funcionaria da seguinte forma
parse("thing1^thing2") #=> "thing1^thing2" parse("thing1") #=> "thing1" parse("thing1^") #=> ERROR ... nothing after the ^ there should be a 'thing'
Isso significaria que a list
corresponderia a uma string que não termine ou comece com um ‘^’. Para ser útil, no entanto, preciso extrair os bits que são os valores com a palavra-chave “as”
rule(:thing) { (str("^").absent? >> any).repeat(1).as(:thing) } rule(:list) { thing >> ( str("^") >> thing).repeat(0) }
Agora, quando a list
corresponde a uma string, recebo uma matriz de hashes de “coisas”.
parse("thing1^thing2") #=> [ {:thing=>"thing1"@0} , {:thing=>"thing2"@7} ]
Na realidade, no entanto, você provavelmente se importa com o que é uma ‘coisa’ … não apenas qualquer coisa irá para lá.
Nesse caso, você deve começar definindo essas regras … porque você não quer usar o analisador para dividir por “^”, em seguida, re-analisar as seqüências de caracteres para descobrir o que eles são feitos.
Por exemplo:
parse("6 + 4 ^ 2") # => [ {:thing=>"6 + 4 "@0}, {:thing=>" 2"@7} ]
E eu provavelmente quero ignorar o white_space em torno das “coisas” e eu provavelmente quero lidar com o 6 the + e o 4 todos separadamente. Quando faço isso, vou ter que jogar fora minha regra “todas as coisas que não são”.