Probablemente lo principal que lo está descartando es que \s
coincide con el espacio horizontal y vertical. Para que coincida con el espacio justo horizontal, uso \h
, y para que coincida con el espacio justo vertical, \v
.
Una pequeña recomendación que haría es evitar incluir las nuevas líneas en el token. También es posible que desee utilizar los operadores de alternancia %
o %%
, como están diseñados para manejar este tipo de trabajo:
grammar Parser {
token TOP {
<headerRow> \n
<valueRow>+ %% \n
}
token headerRow { <.ws>* %% <header> }
token valueRow { <.ws>* %% <value> }
token header { \S+ }
token value { \S+ }
token ws { \h* }
}
El resultado de Parser.parse($dat)
esto es el siguiente:
「ID Name Email
1 test test@email.com
321 stan stan@nowhere.net
」
headerRow => 「ID Name Email」
header => 「ID」
header => 「Name」
header => 「Email」
valueRow => 「 1 test test@email.com」
value => 「1」
value => 「test」
value => 「test@email.com」
valueRow => 「 321 stan stan@nowhere.net」
value => 「321」
value => 「stan」
value => 「stan@nowhere.net」
valueRow => 「」
lo que nos muestra que la gramática ha analizado todo con éxito. Sin embargo, centrémonos en la segunda parte de su pregunta, que desea que esté disponible en una variable para usted. Para hacer eso, deberá proporcionar una clase de acciones que sea muy simple para este proyecto. Simplemente crea una clase cuyos métodos coinciden con los métodos de su gramática (aunque se pueden ignorar los muy simples, como value
/ header
que no requieren un procesamiento especial además de la stringificación). Hay algunas formas más creativas / compactas de manejar el procesamiento de los suyos, pero seguiré con un enfoque bastante rudimentario para la ilustración. Aquí está nuestra clase:
class ParserActions {
method headerRow ($/) { ... }
method valueRow ($/) { ... }
method TOP ($/) { ... }
}
Cada método tiene la firma, ($/)
que es la variable de coincidencia de expresiones regulares. Ahora, preguntemos qué información queremos de cada token. En la fila del encabezado, queremos cada uno de los valores del encabezado, en una fila. Entonces:
method headerRow ($/) {
my @headers = $<header>.map: *.Str
make @headers;
}
Cualquier señal con un cuantificador en ella será tratada como una Positional
, por lo que también podría tener acceso a cada partido encabezado individuo con $<header>[0]
, $<header>[1]
, etc, pero esos son los objetos de los partidos, por lo que sólo stringify rápidamente. El make
comando permite que otros tokens accedan a estos datos especiales que hemos creado.
Nuestra fila de valor se verá idénticamente, porque los $<value>
tokens son lo que nos importa.
method valueRow ($/) {
my @values = $<value>.map: *.Str
make @values;
}
Cuando lleguemos al último método, querremos crear la matriz con hashes.
method TOP ($/) {
my @entries;
my @headers = $<headerRow>.made;
my @rows = $<valueRow>.map: *.made;
for @rows -> @values {
my %entry = flat @headers Z @values;
@entries.push: %entry;
}
make @entries;
}
Aquí puede ver cómo accedemos a las cosas que procesamos headerRow()
y valueRow()
: Usted usa el .made
método. Debido a que hay múltiples valueRows, para obtener cada uno de sus made
valores, necesitamos hacer un mapa (esta es una situación en la que tiendo a escribir mi gramática para tenerla simplemente <header><data>
en la gramática, y destruir los datos como filas múltiples, pero esto es lo suficientemente simple no es tan malo).
Ahora que tenemos los encabezados y las filas en dos matrices, simplemente se trata de convertirlos en una matriz de hashes, lo que hacemos en el for
bucle. El flat @x Z @y
simplemente intercolates los elementos, y la asignación de hash hace lo que queremos decir, pero hay otras maneras de obtener la matriz de hash que desea.
Una vez que haya terminado, solo make
lo hará, y luego estará disponible en made
el análisis:
say Parser.parse($dat, :actions(ParserActions)).made
-> [{Email => test@email.com, ID => 1, Name => test} {Email => stan@nowhere.net, ID => 321, Name => stan} {}]
Es bastante común envolverlos en un método, como
sub parse-tsv($tsv) {
return Parser.parse($tsv, :actions(ParserActions)).made
}
De esa manera solo puedes decir
my @entries = parse-tsv($dat);
say @entries[0]<Name>; # test
say @entries[1]<Email>; # stan@nowhere.net
Nil
. Es bastante árido en lo que respecta a los comentarios, ¿verdad? Para la depuración, descargue Commaide si aún no lo ha hecho, y / o vea ¿Cómo se pueden mejorar los informes de errores en las gramáticas? . TienesNil
porque tu patrón asumió una semántica de retroceso. Mira mi respuesta al respecto. Te recomiendo que evites el retroceso. Ver la respuesta de @ user0721090601 al respecto. Para mayor practicidad y velocidad, vea la respuesta de JJ. Además, la respuesta general introductoria a "Quiero analizar X con Raku. ¿Alguien puede ayudar?" .