javascript - online - parser js
Preguntas de anĂ¡lisis simples utilizando PEG.js (3)
Estoy tratando de envolver mi cabeza alrededor de PEG ingresando gramáticas simples en el área de juegos PEG.js
Ejemplo 1:
- Entrada:
"abcdef1234567ghijklmn8901opqrs"
Salida deseada:
["abcdef", "1234567", "ghijklmn", "8901", "opqrs"]
Salida real:
["abcdef", ["1234567", ["ghijklmn", ["8901", ["opqrs", ""]]]]]
Este ejemplo funciona bastante bien, pero ¿puedo hacer que PEG.js no anide la matriz resultante en un millón de niveles? Supongo que el truco es usar concat()
lugar de join()
algún lugar, pero no puedo encontrar el lugar.
start
= Text
Text
= Numbers Text
/ Characters Text
/ EOF
Numbers
= numbers: [0-9]+ {return numbers.join("")}
Characters
= text: [a-z]+ {return text.join("")}
EOF
= !.
Ejemplo 2:
Mismo problema y código que en el Ejemplo 1, pero cambie la regla de Caracteres a la siguiente, que esperaba que produjera el mismo resultado.
Characters
= text: (!Numbers .)+ {return text.join("")}
La salida resultante es:
[",a,b,c,d,e,f", ["1234567", [",g,h,i,j,k,l,m,n", ["8901", [",o,p,q,r,s", ""]]]]]
¿Por qué obtengo todas estas coincidencias vacías?
Ejemplo 3:
Última pregunta. Esto no funciona en absoluto. ¿Cómo puedo hacer que funcione? ¿Y para los puntos de bonificación, cualquier puntero sobre la eficiencia? Por ejemplo, ¿debería evitar la recursión si es posible?
También agradecería un enlace a un buen tutorial de PEG. He leído ( http://www.codeproject.com/KB/recipes/grammar_support_1.aspx ), pero como pueden ver, necesito más ayuda ...
- Entrada:
''abcdefghijklmnop"qrstuvwxyz"abcdefg''
- Salida deseada:
["abcdefghijklmnop", "qrstuvwxyz", "abcdefg"]
- Salida real:
"abcdefghijklmnop/"qrstuvwxyz/"abcdefg"
start
= Words
Words
= Quote
/ Text
/ EOF
Quote
= quote: (''"'' .* ''"'') Words {return quote.join("")}
Text
= text: (!Quote . Words) {return text.join("")}
EOF
= !.
Ejemplo 1
start
= alnums
alnums
= alnums:(alphas / numbers) {
return alnums;
}
alphas
= alphas:$(alpha+)
numbers
= numbers:$(number+)
number
= [0-9]
alpha
= [a-zA-Z]
Ejemplo 2
ignorar
Ejemplo 3
> ''abcdefghijklmnop"qrstuvwxyz"abcdefg''.split(''"'')
[ ''abcdefghijklmnop'',
''qrstuvwxyz'',
''abcdefg'' ]
Para las versiones actuales de pegjs
, puedes probar:
Ejemplo uno
Entrada: "abcdef1234567ghijklmn8901opqrs"
Salida deseada: ["abcdef", "1234567", "ghijklmn", "8901", "opqrs"]
{
/**
* Deeply flatten an array.
* @param {Array} arr - array to flatten
* @return {Array} - flattened array
*/
const flatten = (arr) => Array.isArray(arr) ? arr.reduce((flat, elt) => flat.concat(Array.isArray(elt) ? flatten(elt) : elt), []) : arr
}
start = result:string {
console.log(JSON.stringify(result))
return result
}
string = head:chars tail:( digits chars? )* {
return flatten([head,tail])
}
chars = [a-z]+ {
return text()
}
digits = $[0-9]+ {
return text()
}
Ejemplo 2
Debe ser fácil de deducir de la respuesta anterior.
Ejemplo 3
Entrada: ''abcdefghijklmnop"qrstuvwxyz"abcdefg''
Salida deseada: ["abcdefghijklmnop", "qrstuvwxyz", "abcdefg"]
{
/**
* Deeply flatten an array.
* @param {Array} arr - array to flatten
* @return {Array} - flattened array
*/
const flatten = (arr) => Array.isArray(arr) ? arr.reduce((flat, elt) => flat.concat(Array.isArray(elt) ? flatten(elt) : elt), []) : arr
}
start = result:string {
console.log(JSON.stringify(result))
return result
}
string = head:chars tail:quote_chars* {
return flatten([head,tail])
}
quote_chars = DQUOTE chars:chars {
return chars
}
chars = [a-z]+ {
return text()
}
DQUOTE = ''"''
Recibí una respuesta en el Grupo de Google PEG.js que me ayudó a encontrar el camino correcto. Estoy publicando respuestas a los tres problemas con la esperanza de que puedan servir como un tutorial rudimentario para otros principiantes de PEG como yo. Tenga en cuenta que no se necesita recursión.
Ejemplo 1:
Esto es sencillo una vez que entiendes los modismos básicos de PEG.
start
= Text+
Text
= Numbers
/ Characters
Numbers
= numbers: [0-9]+ {return numbers.join("")}
Characters
= text: [a-z]+ {return text.join("")}
Ejemplo 2:
El problema aquí es una elección de diseño peculiar en el generador de analizador PEG.js para expresiones Peek (& expr y! Expr). Ambos se asoman al flujo de entrada sin consumir ningún carácter, por lo que asumí incorrectamente que no devolvieron nada. Sin embargo, ambos devuelven una cadena vacía. Espero que el autor de PEG.js cambie este comportamiento, porque (por lo que puedo decir) este es un crucero innecesario que contamina el flujo de salida. Por favor corrígeme si estoy equivocado acerca de esto!
De todos modos, aquí hay una solución:
start
= Text+
Text
= Numbers
/ Words
Numbers
= numbers: [0-9]+ {return numbers.join("")}
Words
= text: Letter+ {return text.join("")}
Letter
= !Numbers text: . {return text}
Ejemplo 3:
El problema es que una expresión como (''"'' .* ''"'')
Nunca puede tener éxito. PEG siempre es codicioso, por lo que .*
Consumirá el resto del flujo de entrada y nunca verá la segunda cita. Aquí hay una solución (que, por cierto, necesita la misma solución Peek que en el Ejemplo 2).
start
= Words+
Words
= QuotedString
/ Text
QuotedString
= ''"'' quote: NotQuote* ''"'' {return quote.join("")}
NotQuote
= !''"'' char: . {return char}
Text
= text: NotQuote+ {return text.join("")}