Pegjs: Possibilité de spécifier le nombre de répétitions (comme dans les regexps)

Créé le 11 août 2011  ·  22Commentaires  ·  Source: pegjs/pegjs

Il serait utile que la grammaire PEG.js permette d'utiliser quelque chose comme des expressions de plage d'expressions régulières de base POSIX. Par exemple:

  • "a"\{1,7\}

correspond a , aa , ..., aaaaaaa

  • "a"\{0,1\}

correspond à la chaîne vide et a

  • "a"\{,6\}

correspond à une chaîne contenant jusqu'à (et y compris) six a

  • "a"\{6,\}

correspond à une chaîne de six a ou plus

  • "a"\{3\}

correspond uniquement aaa , équivalent à "a"\{3,3\}

feature

Commentaire le plus utile

J'aimerais aussi que la répétition compte. Mais je suggérerais une syntaxe légèrement différente. Pegasus est presque identique à pegjs, uniquement pour C#. Voir ici : https://github.com/otac0n/Pegasus/wiki/Syntax-Guide#expressions

Et ils ont implémenté cette fonctionnalité en utilisant ceci : d<3> e<2,> f<1,5>

Tous les 22 commentaires

Je n'implémenterai pas cette fonctionnalité.

La raison principale est qu'il n'y a pas de place dans la grammaire PEG.js pour la syntaxe {m,n} - les accolades sont déjà prises pour les actions et je ne veux pas utiliser de barres obliques inverses comme vous le suggérez (elles sont moches et incompatibles avec les expressions rationnelles Perl qui sont les plus utilisées actuellement et également source d'autres syntaxes PEG.js) ou d'autres délimiteurs (ce serait déroutant).

D'après mon expérience, ce type de répétition limitée se produit principalement sur les parties "lexicales" de la grammaire (règles comme color = "#" hexdigit hexdigit hexdigit hexdigit hexdigit hexdigit ) et pas si souvent. Je pense qu'il est correct d'utiliser simplement des séquences d'expressions et des opérateurs de répétition existants ( * , + , ? ) ici.

J'ai réfléchi et je rouvre ce sujet. Il semble que la possibilité de spécifier un nombre arbitraire de répétitions soit très recherchée par les utilisateurs.

J'aimerais éviter la syntaxe {m,n} type regexp car { et } sont déjà prises pour des actions et les réutiliser créerait une ambiguïté. Je pense actuellement à quelque chose comme ça :

"foo" @ 1..10   // repeat 1 to 10 times
"foo" @ 1..     // repeat at least once
"foo" @ ..10    // repeat at most 10 times

La plus grande question est de savoir quels doivent être les caractères de séparation et comment marquer les plages.

Quant au caractère de séparation, @ me semble sympa. J'envisageais % et # , mais dans mon esprit, le premier est déjà associé à l'interpolation de chaînes (par exemple en Python) et le second aux commentaires (dans différentes langues). Je pense également à sauter complètement le séparateur:

"foo" 1..10   // repeat 1 to 10 times
"foo" 1..     // repeat at least once
"foo" ..10    // repeat at most 10 times

Quant au balisage de gamme, je me suis inspiré de Ruby. Je pensais aussi à - , mais cela ressemble trop à un signe moins. D'un autre côté, : semblable à Python me semble également agréable.

Je ne suis pas sûr des gammes semi-ouvertes. Il serait peut-être préférable de les baliser en utilisant + et - comme ceci :

"foo" @ 1+    // repeat at least once
"foo" @ 10-   // repeat at most 10 times

Des idées ou des commentaires?

Vraiment cool que vous envisagiez de prendre en charge cette fonctionnalité !

J'aime votre suggestion (par défaut):
"foo" @ 1..10 // répéter 1 à 10 fois
"foo" @ 1.. // répéter au moins une fois
"foo" @ ..10 // répéter au plus 10 fois

Je n'aime pas la syntaxe +/- pour les plages semi-ouvertes, la syntaxe à double point est beaucoup plus intuitive et lisible IMO.

La seule chose à laquelle j'ai repensé était d'utiliser "#" vs "@", parce que IMO "#" implique naturellement des nombres/comptages, alors que "@" implique naturellement une référence, donc "#" peut être un peu plus intuitif et lisible (et peut-être pourriez-vous utiliser le "@" à l'avenir pour quelque chose ?). Mais c'est vraiment un problème mineur, et je serais satisfait de la syntaxe "@".

Acclamations!

Juste un commentaire rapide : je pense que @ et % sont de meilleurs choix que # car les surligneurs de syntaxe qui ne prennent pas en charge la grammaire PEG.js, en particulier ceux qui tentent de deviner la syntaxe (par exemple, le surligneur de code de Stack Overflow), interprétera probablement # comme le début d'un commentaire, ce qui le fera apparaître - de manière ennuyeuse - à partir de ce point jusqu'à EOL dans la "couleur du commentaire". Ce n'est pas une préférence basée sur la logique et le raisonnement, bien sûr, mais sur le pragmatisme.

Que diriez-vous de cas spécial pour {num, num} ? Ce qui signifiera une répétition, puisque { , num} et { num, } ne sont pas du code js valide, et {num, num} et { num } sont inutiles.

Ils ne sont pas susceptibles d'être significatifs même si l'action est dans d'autres langues.

J'aime bien ces variantes parmi celles proposées (mais c'est à vous bien sûr de choisir, puisque vous en êtes l'auteur :) ):

// why we need separator, anyway? for me it looks very cool and simple to understand
"foo" 1..10   // repeat 1 to 10 times
"foo" 1..     // repeat at least once
"foo" ..10    // repeat at most 10 times

ou

"foo"@1..10   // repeat 1 to 10 times
"foo"@1..     // repeat at least once
"foo"@..10    // repeat at most 10 times

mais la seconde est moins préférable

l'idée x..y / ..y / x.. a l'air très cool, puisque .. ressemble à un opérateur cohérent grâce à elle.

+/- ne sont pas ok pour moi, car ils confondent et deviennent les opérateurs supplémentaires au-dessus du .. (et + est déjà utilisé)

En y repensant. Cela fonctionnera-t-il?

'foo'<1,5>
'foo'< ,3>
'foo'<2, >

puisque < et > sont actuellement inutilisés par la grammaire

:+1: de ma part, ça a l'air bien.

bien sûr, <,3> équivaut à <0,3> , nous pouvons donc tout aussi bien exiger le nombre minimum. Cela serait conforme à ce que l'ECMA a fait pour les expressions régulières JavaScript.

J'aime le <,> . Mais je suggérerais également que l'utilisation de <3> soit identique à <3,3> .

Je suis d'accord, la syntaxe <> doit correspondre autant que possible au comportement de {} dans RegExp.

Si je ne me trompe pas, il n'est pas nécessaire d'ajouter de délimiteur, sauf si vous souhaitez autoriser les noms de variables dans les plages.

foo 1,2 fighter
bar ,3 tender
baz 4, lurhmann
qux 5 quux

sont tous sans ambiguïté.

@pygy , le problème de ne pas utiliser de délimiteur est qu'il étouffe potentiellement l'évolution de la syntaxe du langage.

Par exemple, si nous voulions utiliser une virgule pour autre chose plus tard, nous aurions maintenant des problèmes de collisions de syntaxe partout. Le limiter à des crochets <> réduit considérablement la surface des virgules et des nombres.

De plus, les gens sont habitués à utiliser le style {1,6} dans RegExps de toute façon.

Je ne suis pas très attaché à la syntaxe, mais je veux cette fonctionnalité, et ce serait formidable si une expression pouvait être utilisée comme valeur de plage.

Mon cas d'utilisation : analyse des littéraux dans les réponses du serveur IMAP, qui ressemblent à {42}\r\n... , où 42 est le nombre de caractères après la nouvelle ligne qui représentent une chaîne (affichée ici sous forme de points de suspension). Puisqu'il n'y a pas de délimiteur de fin pour un littéral IMAP, le comptage de caractères est le seul moyen d'analyser cette réponse.

Qu'en est-il des variables dans les restrictions ? Ceci est très utile pour les messages avec en-tête, contenant sa longueur. Par exemple, la grammaire

  = len:number message:.<len,len> .* {return message;}
number
  = n:[0-9] {return parseInt(n);}

doit analyser

4[__] -> ['[', '_', '_', ']']
4[___] -> ['[', '_', '_', '_']
4[_] -> Error: expected 4 chars, got 3

Ceci est utile pour de nombreux protocoles.

Peut-être utiliser cette syntaxe :
expression |min,max| , les crochets peuvent être utilisés pour les règles de modèle.

Envisagez-vous toujours de mettre cela en œuvre ?
Qu'en est-il de quelque chose de similaire aux gammes ABNF ?

exp *     // 0 or more times
exp 1*    // at least once
exp *10   // up to 10 times
exp 1*10  // 1 to 10 times

Salut. J'ai un format de fichier complexe à analyser. Il est moitié binaire, moitié ASCII.

Voici une version simplifiée du problème :

KK4TesRandom ou KK10TestATestBRandom

La logique:

<StringIndicator><StringLength><String><otherStuff>

Le KK est l'indicateur pour marquer une chaîne. Les chiffres suivants (ici 4 et 10 ) sont la longueur de la chaîne. Puis la chaîne elle-même (ici Test et TestATestB ). La chaîne n'est terminée par aucun motif prévisible. Je dois essentiellement utiliser les informations de longueur. Je dirais que c'est un modèle courant dans les formats de fichiers binaires, mais est-il possible d'analyser avec la grammaire actuelle ?

Merci.

J'implémente une telle chose dans ma branche ranges-dynamic-boundary . La grammaire ressemblera à :

start = len:nx data:.|len| { return data; };
nx = n:$[0-9]+ { return parseInt(n, 10); };

@Mingun wow ! Cela fonctionne comme un charme! Merci beaucoup pour votre mise en œuvre et le court exemple. J'ai fait quelques tests et ça marche super bien. J'espère que votre pull-request sera accepté par le maître.

J'aimerais aussi que la répétition compte. Mais je suggérerais une syntaxe légèrement différente. Pegasus est presque identique à pegjs, uniquement pour C#. Voir ici : https://github.com/otac0n/Pegasus/wiki/Syntax-Guide#expressions

Et ils ont implémenté cette fonctionnalité en utilisant ceci : d<3> e<2,> f<1,5>

Quels sont les peuples autour de cela? Je commence juste à PEGjs en ce moment, alors peut-être que j'essaie de tourner une vis avec un marteau, mais j'essaie juste de faire correspondre entre 1 et 6 chiffres :)

J'utilise ma propre implémentation (voir le # 267 pour la syntaxe, la solution finale prend en charge les nombres, les variables et les blocs de code comme limites) et je préparerai bientôt PR pour le Peggy (rebranding du fork PEG.js qui est maintenu)

Cette page vous a été utile?
0 / 5 - 0 notes