python perl parsing lex

Emulación de la funcionalidad lex like en Perl o Python



parsing (8)

Aquí está el trato. ¿Hay alguna manera de tener cadenas tokenizadas en una línea basada en múltiples expresiones regulares?

Un ejemplo:

Tengo que obtener todas las etiquetas href, su texto correspondiente y algún otro texto basado en una expresión regular diferente. Así que tengo 3 expresiones y me gustaría convertir la línea en tokens y extraer tokens de texto que coincidan con cada expresión.

De hecho, he hecho esto usando flex (que no debe confundirse con Adobe), que es una implementación del buen viejo lex. Lex proporciona una forma elegante de hacerlo ejecutando "acciones" basadas en expresiones. Uno puede controlar la forma en que lex lee un archivo también (lectura basada en bloque / línea).

El problema es que Flex realmente produce código C / C ++ que realmente hace el trabajo de tokenización. Tengo un archivo make que envuelve todas estas cosas. Me preguntaba si Perl / Python puede de alguna manera hacer lo mismo. Es solo que me gustaría hacer todo lo que me gusta en un solo lenguaje de programación.

Tokenizar es solo una de las cosas que quiero hacer como parte de mi aplicación.

Además de Perl o Python, ¿puede cualquier lenguaje (funcional también) hacer esto?

Leí sobre PLY y ANTLR aquí ( Análisis, ¿dónde puedo obtener información al respecto? ).

Pero, ¿hay alguna manera de hacerlo naturalmente en Python? Perdonen mi ignorancia, pero ¿se usan estas herramientas en cualquier producto / servicio popular?

Gracias.


¿Has mirado PyParsing ?

Desde su página de inicio:

Aquí hay un programa para analizar "Hello, World!" (o cualquier saludo del formulario ",!"):

from pyparsing import Word, alphas greet = Word( alphas ) + "," + Word( alphas ) + "!" # <-- grammar defined here hello = "Hello, World!" print hello, "->", greet.parseString( hello )

El programa da como resultado lo siguiente:

Hello, World! -> [''Hello'', '','', ''World'', ''!'']


Desde perlop :

Una expresión útil para los escáneres de tipo lex es //G.../gc . Puede combinar varias expresiones regulares como esta para procesar una cadena parte por parte, realizando diferentes acciones según corresponda a la expresión regular. Cada expresión regular intenta coincidir con la anterior.

LOOP: { print(" digits"), redo LOOP if //G/d+/b[,.;]?/s*/gc; print(" lowercase"), redo LOOP if //G[a-z]+/b[,.;]?/s*/gc; print(" UPPERCASE"), redo LOOP if //G[A-Z]+/b[,.;]?/s*/gc; print(" Capitalized"), redo LOOP if //G[A-Z][a-z]+/b[,.;]?/s*/gc; print(" MiXeD"), redo LOOP if //G[A-Za-z]+/b[,.;]?/s*/gc; print(" alphanumeric"), redo LOOP if //G[A-Za-z0-9]+/b[,.;]?/s*/gc; print(" line-noise"), redo LOOP if //G[^A-Za-z0-9]+/gc; print ". That''s all!/n"; }



Parece que realmente solo quieres analizar HTML, te recomiendo mirar alguno de los maravillosos paquetes para hacerlo:

¡O! Puede usar un analizador como uno de los siguientes:

Este ejemplo es de la documentación de BeautifulSoup:

from BeautifulSoup import BeautifulSoup, SoupStrainer import re links = SoupStrainer(''a'') [tag for tag in BeautifulSoup(doc, parseOnlyThese=links)] # [<a href="http://www.bob.com/">success</a>, # <a href="http://www.bob.com/plasma">experiments</a>, # <a href="http://www.boogabooga.net/">BoogaBooga</a>] linksToBob = SoupStrainer(''a'', href=re.compile(''bob.com/'')) [tag for tag in BeautifulSoup(doc, parseOnlyThese=linksToBob)] # [<a href="http://www.bob.com/">success</a>, # <a href="http://www.bob.com/plasma">experiments</a>]


Si está específicamente analizando enlaces de páginas web, el módulo WWW :: Mechanize de Perl resolverá las cosas de una manera muy elegante. Aquí hay un programa de ejemplo que toma la primera página de y analiza todos los enlaces, imprimiendo su texto y las URL correspondientes:

#!/usr/bin/perl use strict; use warnings; use WWW::Mechanize; my $mech = WWW::Mechanize->new; $mech->get("http://.com/"); $mech->success or die "Oh no! Couldn''t fetch .com"; foreach my $link ($mech->links) { print "* [",$link->text, "] points to ", $link->url, "/n"; }

En el bucle principal, cada $link es un objeto WWW :: Mechanize :: Link , por lo que no solo está obligado a obtener el texto y la URL.

Todo lo mejor,

Pablo


Si su problema tiene algo que ver con el raspado de la web, le recomiendo consultar Web :: Scraper , que proporciona una fácil selección de elementos a través de los selectores CSSath respectivamente. Tengo una charla (alemana) sobre Web :: Scraper , pero si la ejecutas a través de babelfish o simplemente miras los ejemplos del código, eso puede ayudarte a obtener una visión general rápida de la sintaxis.

El análisis de mano de HTML es oneroso y no le dará mucho de usar uno de los analizadores de HTML prefabricados. Si su HTML tiene una variación muy limitada, puede usar expresiones regulares inteligentes, pero si ya está analizando las herramientas del analizador de núcleo duro, suena como si su HTML fuera mucho más regular que lo normal para analizarlo. expresiones regulares.


Modificar el ejemplo de Bruno para incluir la comprobación de errores:

my $input = "..."; while (1) { if ($input =~ //G(/w+)/gc) { print "word: ''$1''/n"; next } if ($input =~ //G(/s+)/gc) { print "whitespace: ''$1''/n"; next } if ($input !~ //G/z/gc) { print "tokenizing error at character " . pos($input) . "/n" } print "done!/n"; last; }

(Tenga en cuenta que el uso de escalar // g es, desafortunadamente, el único lugar donde no puede evitar el uso de las variables de $ 1, etc.).


También revise pQuery como una muy buena manera Perlish de hacer este tipo de cosas ...

use pQuery; pQuery( ''http://www.perl.com'' )->find( ''a'' )->each( sub { my $pQ = pQuery( $_ ); say $pQ->text, '' -> '', $pQ->toHtml; } ); # prints all HTML anchors on www.perl.com # => link text -> anchor HTML

Sin embargo, si su requerimiento está más allá de HTML / Web, aquí está el anterior "¡Hola Mundo!" ejemplo en Parse :: RecDescent ...

use strict; use warnings; use Parse::RecDescent; my $grammar = q{ alpha : //w+/ sep : /,|/s/ end : ''!'' greet : alpha sep alpha end { shift @item; return /@item } }; my $parse = Parse::RecDescent->new( $grammar ); my $hello = "Hello, World!"; print "$hello -> @{ $parse->greet( $hello ) }"; # => Hello, World! -> Hello , World !

Probablemente demasiado de un martillo grande para romper esta tuerca ;-)