Pegjs: Posibilidad de especificar el número de repeticiones (como en las expresiones regulares)

Creado en 11 ago. 2011  ·  22Comentarios  ·  Fuente: pegjs/pegjs

Sería útil si la gramática de PEG.js permitiera el uso de expresiones de rango de expresiones regulares básicas POSIX. P.ej:

  • "a"\{1,7\}

coincide con a , aa , ..., aaaaaaa

  • "a"\{0,1\}

coincide con la cadena vacía y a

  • "a"\{,6\}

coincide con una cadena con hasta (e incluyendo) seis a 's

  • "a"\{6,\}

coincide con una cadena de seis o más a 's

  • "a"\{3\}

coincide solo con aaa , siendo equivalente a "a"\{3,3\}

feature

Comentario más útil

También me encantaría contar las repeticiones. Pero sugeriría una sintaxis ligeramente diferente. Pegasus es casi idéntico a pegjs, solo para C#. Consulte aquí: https://github.com/otac0n/Pegasus/wiki/Syntax-Guide#expressions

E implementaron esta característica usando esto: d<3> e<2,> f<1,5>

Todos 22 comentarios

No implementaré esta función.

La razón principal es que no hay espacio en la gramática de PEG.js para la sintaxis {m,n} : las llaves ya están tomadas para las acciones y no quiero usar barras invertidas como sugieres (son feas y no compatibles con expresiones regulares de Perl, que son las más utilizadas ahora y también fuente de otra sintaxis de PEG.js) u otros delimitadores (eso sería confuso).

En mi experiencia, este tipo de repetición limitada ocurre principalmente en las partes "léxicas" de la gramática (reglas como color = "#" hexdigit hexdigit hexdigit hexdigit hexdigit hexdigit ) y no tan a menudo. Creo que está bien usar secuencias de expresiones y operadores de repetición existentes ( * , + , ? ) allí.

He reconsiderado y estoy reabriendo este tema. Parece que los usuarios buscan mucho la capacidad de especificar un número arbitrario de repeticiones.

Me gustaría evitar la sintaxis de {m,n} similar a expresiones regulares porque { y } ya se han tomado para acciones y su reutilización crearía ambigüedad. Actualmente estoy pensando en algo como esto:

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

La pregunta más importante es cuáles deberían ser los caracteres de separación y cómo marcar los rangos.

En cuanto al carácter de separación, @ me parece agradable. Estaba considerando % y # , pero en mi opinión, el primero ya está asociado con la interpolación de cadenas (por ejemplo, en Python) y el segundo con comentarios (en varios idiomas). También estoy pensando en omitir el separador por completo:

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

En cuanto al marcado de rango, me inspiré en Ruby. También estaba pensando en - , pero se parece demasiado a un signo menos. Por otro lado, : similar a Python también me parece agradable.

No estoy seguro acerca de los rangos semiabiertos. Tal vez sería mejor marcarlos usando + y - así:

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

¿Alguna idea o comentario?

¡Realmente genial que planees admitir esta función!

Me gusta tu sugerencia (predeterminada):
"foo" @ 1..10 // repetir de 1 a 10 veces
"foo" @ 1.. // repetir al menos una vez
"foo" @ ..10 // repetir como máximo 10 veces

No me gusta la sintaxis +/- para rangos semiabiertos, la sintaxis de doble punto es mucho más intuitiva y legible en mi opinión.

Lo único que tuve dudas fue usar "#" frente a "@", porque IMO "#" implica naturalmente números/conteo, mientras que "@" naturalmente implica una referencia, por lo que "#" puede ser un poco más intuitivo y legible. (¿y tal vez podrías usar la "@" en el futuro para algo?). Pero eso es realmente un problema menor, y estaría feliz con la sintaxis "@".

¡Salud!

Solo un comentario rápido: creo que @ y % son mejores opciones que # porque los resaltadores de sintaxis que no son compatibles con la gramática PEG.js, especialmente aquellos que intentan adivinar la sintaxis (por ejemplo, el resaltador de código de Stack Overflow), probablemente interpretará # como el comienzo de un comentario, lo que hará que se muestre, molesto, desde ese punto hasta EOL en el "color de comentario". Esta no es una preferencia basada en la lógica y el razonamiento, por supuesto, sino en el pragmatismo.

¿Qué tal si hacemos un caso especial para {num, num} por igual? Lo que significará repetición, ya que { , num} y { num, } no son código js válido, y {num, num} y { num } tienen sentido.

No es probable que sean significativos incluso si la acción es de otros idiomas.

Me gustan estas variantes entre las sugeridas (pero, por supuesto, depende de ti elegir, ya que eres el autor :)):

// 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

o

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

pero el segundo es menos preferible

la idea x..y / ..y / x.. se ve muy bien, ya que .. parece un operador consistente gracias a ella.

+/- no están bien para mí, porque confunden y se convierten en los operadores adicionales por encima de .. (y + ya se usa)

Pensándolo de nuevo. ¿Funcionarán estos?

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

ya que < y > actualmente no son utilizados por la gramática

:+1: de mi parte, eso se ve bien.

por supuesto, <,3> es equivalente a <0,3> , por lo que también podemos solicitar el número mínimo. Esto sería congruente con lo que ECMA ha hecho para las expresiones regulares de JavaScript.

Me gusta el <,> . Pero también sugeriría que el uso de <3> sea lo mismo que <3,3> .

Estoy de acuerdo, la sintaxis <> debe asignarse directamente al comportamiento de {} en RegExp tanto como sea posible.

Si no me equivoco, no es necesario agregar ningún delimitador, a menos que desee permitir nombres de variables en los rangos.

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

son todos inequívocos.

@pygy , el problema de no usar un delimitador es que sofoca potencialmente la evolución de la sintaxis del lenguaje.

Por ejemplo, si quisiéramos usar la coma para otra cosa más adelante, ahora tendríamos problemas con las colisiones de sintaxis por todas partes. Limitarlo a <> corchetes reduce sustancialmente el área de superficie de comas y números.

Además, la gente está acostumbrada a usar el estilo {1,6} en RegExps de todos modos.

No estoy muy convencido de la sintaxis, pero sí quiero esta característica, y sería genial si se pudiera usar una expresión como un valor de rango.

Mi caso de uso: análisis de literales en las respuestas del servidor IMAP, que se ven como {42}\r\n... , donde 42 es la cantidad de caracteres después de la nueva línea que representa una cadena (que se muestra aquí como puntos suspensivos). Dado que no hay un delimitador final para un literal IMAP, el recuento de caracteres es la única forma de analizar esta respuesta.

¿Qué hay de las variables en las restricciones? Esto es muy útil para mensajes con encabezado, que contiene su longitud. Por ejemplo, la gramática

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

debe analizar

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

Esto es útil para muchos protocolos.

Se puede usar esa sintaxis:
expression |min,max| , entonces los corchetes angulares se pueden usar para las reglas de plantilla.

¿Todavía estás considerando implementar esto?
¿Qué tal algo similar a los rangos ABNF ?

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

Hola. Tengo un formato de archivo complejo para analizar. Es mitad binario, mitad ASCII.

Aquí una versión simplificada del problema:

KK4TesRandom o KK10TestATestBRandom

La lógica:

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

El KK es el indicador para marcar una cadena. Los siguientes dígitos (aquí 4 y 10 ) son la longitud de la cadena. Luego, la cadena en sí (aquí Test y TestATestB ). La cadena no termina con ningún patrón predecible. Básicamente tengo que usar la información de longitud. Diría que este es un patrón común en los formatos de archivos binarios, pero ¿es posible analizarlo con la gramática actual?

Gracias.

Implemento tal cosa en mi branch ranges-dynamic-boundary . La gramática se verá así:

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

@Mingun guau! ¡Eso funciona a las mil maravillas! Muchas gracias por su implementación y el breve ejemplo. Hice algunas pruebas y funciona increíble. Espero que su solicitud de extracción sea aceptada por el maestro.

También me encantaría contar las repeticiones. Pero sugeriría una sintaxis ligeramente diferente. Pegasus es casi idéntico a pegjs, solo para C#. Consulte aquí: https://github.com/otac0n/Pegasus/wiki/Syntax-Guide#expressions

E implementaron esta característica usando esto: d<3> e<2,> f<1,5>

¿Cuáles son las soluciones de la gente para esto? Me estoy metiendo en PEGjs en este momento, así que tal vez esté tratando de girar un tornillo con un martillo, pero solo estoy tratando de hacer coincidir entre 1 y 6 dígitos :)

Estoy usando mi propia implementación (vea el #267 para la sintaxis, la solución final admite números, variables y bloques de código como límites) y pronto prepararé relaciones públicas para Peggy (cambio de marca de la bifurcación PEG.js que se mantiene)

¿Fue útil esta página
0 / 5 - 0 calificaciones