Los parser combinators son el punto medio que le falta a tu código entre regex y tree-sitter

Un parser parcial recibe un string y devuelve una tupla con el valor extraído y el resto sin consumir; encadenarlos permite construir gramáticas completas sin la fragilidad de regex ni el peso de tree-sitter. El artículo muestra cómo definir pHello, pIgnoreWhitespace y pInteger, combinarlos con pSeq y pMap, y hasta transformar la salida de ping en un objeto estructurado.
Regex se vuelve un desastre en tareas complejas, y tree-sitter suele ser excesivo; para ese terreno intermedio, los parser combinators son perfectos.
- ArneCode
¡Me encantan las animaciones, hacen que sea intuitivo entender lo que está pasando!
Una desventaja que creo que tienen los parser combinators, por ejemplo en comparación con las librerías de generadores de parsers (donde el parser se genera a partir de un archivo de gramática separado), es que tienes que añadir un montón de código de mapeo/desempaquetado. En mi opinión, esto hace que los parsers sean más difíciles de leer.
Como intento de mejorar esto, he estado trabajando en una librería de parser combinators en Rust.
Añade dos combinadores extra (capture y bind) que pueden almacenar los resultados de los parsers en buckets (bind) y usar los valores almacenados en estos buckets más tarde para construir resultados (capture).
Esto te permite eliminar el código de desempaquetado/mapeo y separar la gramática de la construcción del resultado.
Si tienes tiempo, ¡agradecería mucho tus comentarios sobre esto!
Puedes encontrarlo aquí: https://github.com/ArneCode/marser
- marginalia_nu
No entiendo por qué esto no puede estar en una sola página. Hace que sea realmente difícil volver a los "capítulos" anteriores a medida que obtienes nueva información cuando es una presentación de diapositivas. Tampoco se puede buscar.
¿Parece que estamos reintroduciendo innecesariamente limitaciones del medio en papel que no existen en los medios digitales por extrañas razones estéticas?
- akst
Creo que este sitio web es realmente genial y me encanta este tema.
Pero creo que podrías querer probar esta página en pantallas más pequeñas, hay muy poco espacio de pantalla para el contenido de interés, la mitad superior derecha tiene mucho relleno, el contenido desplazable básicamente tiene 1/3 del espacio de pantalla disponible, el lado izquierdo tiene otro 1/3.
Mira, tu sitio web, tu visión, lo entiendo y respeto que estés intentando algo diferente con la interfaz, pero si tu objetivo aquí es comunicar tus ideas, como lector agradecería tener más espacio en pantalla para el contenido. Cuando hice clic en el enlace para ver esta publicación en concreto, simplemente no me interesan tus otras publicaciones (o al menos hasta que haya leído la que me tomé la molestia de leer).
Por si sirve de algo, ahora mismo estoy usando un MacBook Air.
- BoppreH
Si estás en Python y tu problema es demasiado grande para una sola regex, pero demasiado pequeño para un parser completo como el del artículo, puedo recomendar el re.Scanner[0] integrado. Es un tokenizador basado en regex[1] (así que no hay parsing recursivo) en el módulo `re`, que por alguna razón falta por completo en cualquier documentación oficial.
Le das un patrón para cada tipo de token, y una función para procesar cada coincidencia, y obtienes una lista de tokens procesados.
Lo importante es que procesa la lista en una sola pasada y asegura que las coincidencias sean contiguas, mientras que un `re.findall` ingenuo con grupos de captura ignorará los caracteres no coincidentes. También obtienes una referencia al scanner en ejecución, para que puedas registrar la ubicación de la coincidencia para reportar errores.
import re
# Initialize the scanner.
scanner = re.Scanner([
(r"\d+", lambda scanner, token: ('COUNT', int(token))),
(r"\w+", lambda scanner, token: ('ANIMAL', token.removesuffix('s'))),
(r"[,. ]", None), # None -> skip token.
])
# Scan a sample string.
results, remainder = scanner.scan("45 pigeons, 23 cows, 11 spiders.")
# Ensure we parsed the whole thing.
assert not remainder
print(results)
# [('COUNT', 45),
# ('ANIMAL', 'pigeon'),
# ('COUNT', 23),
# ('ANIMAL', 'cow'),
# ('COUNT', 11),
# ('ANIMAL', 'spider')]
[0]: https://stackoverflow.com/a/693818/252218
[1]: https://en.wikipedia.org/wiki/Lexical_analysis#Tokenization
- boomlinde
Probablemente la primera dirección no debería analizarse como una dirección IP, ya que también puede ser un nombre de host. Puede parecer una nimiedad, pero crea la oportunidad de demostrar qué hacer cuando esperas cualquiera de más de un tipo de construcción.
El artículo fue algo difícil de leer debido al área limitada dedicada al cuerpo del texto. Tuve que desplazarme en varias páginas a pesar de los capítulos cortos.