2012-06-29 13 views
5

Tengo un convertidor bbcode -> html que responde al evento de cambio en un área de texto. Actualmente, esto se hace usando una serie de expresiones regulares, y hay una cantidad de casos patológicos. Siempre he querido afilar el lápiz en esta gramática, pero no quería meterme en el afeitado de yak. Pero ... recientemente me di cuenta de pegjs, que parece una implementación bastante completa de la generación de analizadores PEG. Tengo la mayor parte de la gramática especificada, pero ahora me pregunto si este es un uso apropiado de un analizador completo.Usando PEG Parser para el análisis de BBCode: pegjs o ... ¿qué?

Mis preguntas específicas son:

  1. Como mi aplicación se basa en la traducción de lo que pueda para HTML y dejando el resto como texto sin formato, no implementar BBCode usando un analizador que puede fallar en un sentido esto error de sintaxis ? Por ejemplo: [url=/foo/bar]click me![/url] ciertamente se espera que tenga éxito una vez que se ingrese el corchete de cierre en la etiqueta de cierre. Pero, ¿qué vería el usuario mientras tanto? Con la expresión regular, puedo ignorar cosas que no coinciden y tratarlas como texto normal para fines de vista previa. Con una gramática formal, no sé si esto es posible porque confío en crear el HTML de un árbol de análisis sintáctico y lo que falla es un análisis ... ¿qué?

  2. No tengo claro dónde deben realizarse las transformaciones. En un analizador formal basado en lex/yacc, tendría los archivos de cabecera y los símbolos que denotan el tipo de nodo. En pegjs, obtengo matrices anidadas con el texto del nodo. Puedo emitir el código traducido como una acción del analizador generado por pegjs, pero parece un olor a código para combinar un analizador y un emisor. Sin embargo, si llamo PEG.parse.parse(), yo vuelva algo como esto:

[ 
     [ 
      "[", 
      "img", 
      "", 
      [ 
      "/", 
      "f", 
      "o", 
      "o", 
      "/", 
      "b", 
      "a", 
      "r" 
      ], 
      "", 
      "]" 
     ], 
     [ 
      "[/", 
      "img", 
      "]" 
     ] 
    ]

dada una gramática como:

document 
    = (open_tag/close_tag/new_line/text)* 

open_tag 
    = ("[" tag_name "="? tag_data? tag_attributes? "]") 


close_tag 
    = ("[/" tag_name "]") 

text 
    = non_tag+ 

non_tag 
    = [\n\[\]] 

new_line 
    = ("\r\n"/"\n") 

estoy abreviando la gramática, por supuesto, pero captar la idea. Entonces, si lo nota, no hay información contextual en la matriz de matrices que me diga qué tipo de nodo tengo y me queda hacer comparaciones de cadenas nuevamente aunque el analizador ya lo haya hecho. Espero que sea posible definir devoluciones de llamada y usar acciones para ejecutarlas durante un análisis, pero hay poca información disponible en la Web sobre cómo se podría hacer eso.

¿Estoy ladrando el árbol equivocado? ¿Debería recurrir a la exploración de expresiones regulares y olvidarme del análisis sintáctico?

Gracias

+0

Steve, tu pregunta es muy interesante (+1), solo quiero hacer lo mismo en una extensión: analizar BBCode en un área de texto (lamentablemente este es el formato que todavía está usando un foro), y crear un "live "vista previa del texto escrito usando PEG.js o cualquier otra cosa excepto expresiones regulares. ¿Has logrado crear la gramática para el analizador de BBCode? ¿No podrías compartir tu solución a través de GitHub o cualquier otra cosa? Eso me ayudaría mucho. Muchas gracias de antemano! – Sk8erPeter

+0

Utilicé [pacerjk's bbcode parser] (https://github.com/patorjk/Extendible-BBCode-Parser). Funciona muy bien y puede ajustarse a sus propias necesidades si tiene etiquetas especiales. –

+0

Gracias, ya he visto esta biblioteca, pero usa expresiones regulares, lo que quería evitar, porque teóricamente, el análisis de BBCode con expresiones regulares no se puede hacer sin fallas ([»» enlace] (http: // kore- nordmann.de/blog/do_NOT_parse_using_regexp.html)) en algunos casos, por ejemplo al anidarlos entre ellos, etc. Por eso quería hacerlo usando el formalismo gramatical de expresión de análisis. Entonces, ¿no trataste de mejorar la gramática que comenzaste? :) ¿No podrías compartir la base de esto? :) – Sk8erPeter

Respuesta

2

En cuanto a su primera pregunta que tengo que tosay una vista previa en vivo va a ser difícil. Los problemas que señaló con respecto a que el analizador no entenderá que la entrada es "trabajo en progreso" son correctos. Peg.js te dice en qué punto está el error, así que tal vez podrías tomar esa información y volver a analizar algunas palabras y analizarlas o, si falta una etiqueta de finalización, intenta agregarla al final.

La segunda parte de su pregunta es más fácil, pero su gramática no se verá tan bien después. Básicamente lo que hace es devoluciones de llamada de venta sobre todas las reglas, así que por ejemplo

text 
    = text:non_tag+ { 
    // we captured the text in an array and can manipulate it now 
    return text.join(""); 
    } 

En el momento en que tiene que escribir estas devoluciones de llamada en línea en su gramática. Estoy haciendo muchas de estas cosas en el trabajo ahora mismo, así que podría hacer una petición de extracción a peg.js para arreglar eso. Pero no estoy seguro de cuándo encontrar el momento para hacer esto.

1

Pruebe algo así como esta regla de reemplazo. Estás en el camino correcto; solo tienes que decirlo para armar los resultados.

texto = resultado: non_tag + {return result.join (''); }

3

Primera pregunta (gramatical para los textos incompletos):

Puede añadir

incomplete_tag = ("[" tag_name "="? tag_data? tag_attributes?) 
//       the closing bracket is omitted ---^ 

despuésopen_tag y cambiar document para incluir una etiqueta incompleta al final. El truco es que le proporcionas al analizador todas las producciones necesarias al siempre parse, pero las válidas son las primeras. Luego puede ignorar incomplete_tag durante la vista previa en vivo.

Segunda pregunta (cómo incluir acciones):

usted escribe Socalled acciones después de expresiones. Una acción es un código Javascript encerrado entre llaves y está permitido después de una expresión pegjs, i. mi. también en el medio de una producción!

En la práctica, las acciones como { return result.join("") } casi siempre son necesarias porque pegjs se divide en caracteres individuales. También se pueden devolver matrices anidadas complicadas. Por lo tanto, generalmente escribo funciones auxiliares en el inicializador pegjs en la parte superior de la gramática para mantener las acciones pequeñas. Si elige los nombres de las funciones con cuidado, la acción se autodetecta.

Para un examen, vea PEG for Python style indentation. Descargo de responsabilidad: esta es una respuesta mía.

Cuestiones relacionadas