La principale chose qui le jette est probablement celle qui \s
correspond à l'espace horizontal et vertical. Pour correspondre à l' espace horizontal juste, l' utilisation \h
, et pour correspondre à l' espace juste vertical, \v
.
Une petite recommandation que je ferais est d'éviter d'inclure les nouvelles lignes dans le jeton. Vous pouvez également utiliser les opérateurs d'alternance %
ou %%
, comme ils sont conçus pour gérer ce type de travail:
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* }
}
Le résultat de Parser.parse($dat)
ceci est le suivant:
「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 => 「」
ce qui nous montre que la grammaire a tout analysé avec succès. Cependant, concentrons-nous sur la deuxième partie de votre question, que vous souhaitez qu'elle soit disponible dans une variable pour vous. Pour ce faire, vous devrez fournir une classe d'actions très simple pour ce projet. Vous créez simplement une classe dont les méthodes correspondent aux méthodes de votre grammaire (bien que des méthodes très simples, comme value
/ header
qui ne nécessitent pas de traitement spécial en plus de la stringification, puissent être ignorées). Il existe des moyens plus créatifs / compacts de gérer le traitement de la vôtre, mais je vais suivre une approche assez rudimentaire pour l'illustration. Voici notre classe:
class ParserActions {
method headerRow ($/) { ... }
method valueRow ($/) { ... }
method TOP ($/) { ... }
}
Chaque méthode a la signature ($/)
qui est la variable de correspondance d'expression régulière. Alors maintenant, demandons quelles informations nous voulons de chaque jeton. Dans la ligne d'en-tête, nous voulons chacune des valeurs d'en-tête, dans une ligne. Donc:
method headerRow ($/) {
my @headers = $<header>.map: *.Str
make @headers;
}
Tout jeton avec un quantificateur sur elle sera traitée comme Positional
, afin que nous puissions également accéder à chaque match d' en- tête individuel avec $<header>[0]
, $<header>[1]
etc. Mais ce sont des objets de match, alors on les stringify rapidement. La make
commande permet à d'autres jetons d'accéder à ces données spéciales que nous avons créées.
Notre ligne de valeur sera identique, car les $<value>
jetons sont ce dont nous nous soucions.
method valueRow ($/) {
my @values = $<value>.map: *.Str
make @values;
}
Lorsque nous arriverons à la dernière méthode, nous voudrons créer le tableau avec des hachages.
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;
}
Ici, vous pouvez voir comment nous accédons aux trucs que nous avons traités headerRow()
et valueRow()
: Vous utilisez la .made
méthode. Parce qu'il y a plusieurs ValueRows, pour obtenir chacune de leurs made
valeurs, nous devons faire une carte (c'est une situation où j'ai tendance à écrire ma grammaire pour avoir simplement <header><data>
dans la grammaire, et définir les données comme étant plusieurs lignes, mais c'est assez simple c'est pas trop mal).
Maintenant que nous avons les en-têtes et les lignes dans deux tableaux, il s'agit simplement d'en faire un tableau de hachages, ce que nous faisons dans la for
boucle. Le flat @x Z @y
juste interconnecte les éléments, et l'affectation de hachage fait ce que nous voulons dire, mais il existe d'autres façons d'obtenir le tableau dans le hachage souhaité.
Une fois que vous avez terminé, vous venez de le make
faire, puis il sera disponible dans le made
de l'analyse:
say Parser.parse($dat, :actions(ParserActions)).made
-> [{Email => test@email.com, ID => 1, Name => test} {Email => stan@nowhere.net, ID => 321, Name => stan} {}]
Il est assez courant de les intégrer dans une méthode, comme
sub parse-tsv($tsv) {
return Parser.parse($tsv, :actions(ParserActions)).made
}
De cette façon, vous pouvez simplement dire
my @entries = parse-tsv($dat);
say @entries[0]<Name>; # test
say @entries[1]<Email>; # stan@nowhere.net
Nil
. C'est assez stérile en ce qui concerne les commentaires, non? Pour le débogage, téléchargez la virgule si vous ne l'avez pas déjà fait et / ou consultez Comment améliorer le rapport d'erreurs dans les grammaires? . Vous avez obtenuNil
parce que votre modèle supposait une sémantique de retour arrière. Voir ma réponse à ce sujet. Je vous recommande d'éviter le retour en arrière. Voir la réponse de @ user0721090601 à ce sujet. Pour la praticité et la vitesse, voir la réponse de JJ. Aussi, réponse générale d'introduction à "Je veux analyser X avec Raku. Quelqu'un peut-il aider?" .