Domanda

Ecco l'affare. C'è un modo per avere le stringhe tokenizzate in una linea basata su più regex?

Un esempio:

Devo ottenere tutti i tag href, il loro testo corrispondente e qualche altro testo basato su una regex diversa. Quindi ho 3 espressioni e vorrei tokenizzare la linea ed estrarre token di testo corrispondenti a ogni espressione.

In realtà l'ho fatto usando flex (da non confondere con Adobe), che è un'implementazione del buon vecchio lex. lex fornisce un modo elegante per farlo eseguendo "azioni" basato sulle espressioni. Si può controllare la strada lettura lex anche di un file (lettura basata su blocco / linea).

Il problema è che flex produce effettivamente codice C / C ++ che svolge effettivamente il lavoro di tokenizzazione. Ho un crea un file che avvolge tutte queste cose. Mi chiedevo se perl / python potesse in qualche modo fare la stessa cosa. È solo che vorrei fare tutto Mi piace in un solo linguaggio di programmazione stesso.

Il token è solo una delle cose che voglio fare come parte della mia applicazione.

A parte perl o python, qualsiasi linguaggio (anche funzionale) può farlo?

Ho letto di PLY e ANTLR qui ( Analisi, dove è possibile Lo imparo ).

Ma c'è un modo per farlo naturalmente in Python stesso? scusate la mia ignoranza, ma questi strumenti sono utilizzati in prodotti / servizi popolari?

Grazie.

È stato utile?

Soluzione

Se stai specificatamente dopo aver analizzato i link dalle pagine Web, allora WWW: : Il modulo Mechanize ti farà scoprire le cose in un modo molto elegante. Ecco un programma di esempio che acquisisce la prima pagina di Stack Overflow e analizza tutti i collegamenti, stampandone il testo e gli URL corrispondenti:

#!/usr/bin/perl
use strict;
use warnings;
use WWW::Mechanize;

my $mech = WWW::Mechanize->new;

$mech->get("http://stackoverflow.com/");

$mech->success or die "Oh no! Couldn't fetch stackoverflow.com";

foreach my $link ($mech->links) {
    print "* [",$link->text, "] points to ", $link->url, "\n";
}

Nel ciclo principale, ogni $ link è WWW :: Mechanize :: Link oggetto, quindi non sei solo costretto a ottenere il testo e l'URL.

Tutto il meglio,

Paul

Altri suggerimenti

Consulta la documentazione per i seguenti moduli su CPAN

HTML :: TreeBuilder

HTML :: TableExtract

e

Parse :: RecDescent

Ho usato questi moduli per elaborare pagine Web abbastanza grandi e complesse.

Sembra che tu voglia davvero analizzare l'HTML, ti consiglio di guardare uno dei meravigliosi pacchetti per farlo:

O! Puoi utilizzare un parser come uno dei seguenti:

  • PyParsing
  • DParser - Un parser GLR con buoni collegamenti in pitone.
  • ANTLR - Un generatore di parser decente ricorsivo che può generare codice Python.

Questo esempio è tratto da BeautifulSoup Documentazione :

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

Hai guardato PyParsing ?

Dalla loro homepage:

Ecco un programma per analizzare " Ciao, mondo! " (o qualsiasi messaggio di saluto del modulo " ;,! "):

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

Il programma genera quanto segue:

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

Se il tuo problema ha qualcosa a che fare con il web scraping, ti consiglio di guardare Web :: Scraper , che offre una facile selezione degli elementi tramite selettori CSS e XPath rispettivamente. Ho un (tedesco) talk sul Web :: Scraper , ma se lo esegui attraverso babelfish o semplicemente guardi gli esempi di codice, ciò può aiutarti a ottenere una rapida panoramica della sintassi.

L'analisi HTML della mano è onerosa e non ti darà molto di più utilizzando uno dei parser HTML premade. Se il tuo HTML ha una variazione molto limitata, puoi farlo usando espressioni regolari intelligenti, ma se stai già rompendo gli strumenti di parser hard-core, sembra che il tuo HTML sia molto più regolare di ciò che è sano per analizzare espressioni regolari.

Da perlop :

  

Un linguaggio utile per gli scanner lex-like   è /\G.../gc . Puoi combinare   diverse regexps come questa per elaborare a   stringa parte per parte, facendo diversamente   azioni a seconda di quale regexp   abbinato. Ogni regexp cerca di abbinare   dove il precedente si interrompe.

 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";
    }

Dai un'occhiata anche a pQuery come un modo perlish davvero carino di fare questo tipo di roba ....

use pQuery;

pQuery( 'http://www.perl.com' )->find( 'a' )->each( 
    sub {
        my $pQ = pQuery( 

Dai un'occhiata anche a pQuery come un modo perlish davvero carino di fare questo tipo di roba ....

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 !

Tuttavia, se il tuo requisito è oltre HTML / Web, ecco il precedente "Ciao mondo!" esempio in Parse :: RecDescent ...

<*>

Probabilmente troppo di un grosso martello per rompere questo dado ;-)

); say $pQ->text, ' -> ', $pQ->toHtml; } ); # prints all HTML anchors on www.perl.com # => link text -> anchor HTML

Tuttavia, se il tuo requisito è oltre HTML / Web, ecco il precedente "Ciao mondo!" esempio in Parse :: RecDescent ...

<*>

Probabilmente troppo di un grosso martello per rompere questo dado ;-)

Modifica dell'esempio di Bruno per includere il controllo degli errori:

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;
}

(Nota che usare scalare // g è purtroppo l'unico posto in cui non puoi davvero evitare di usare le variabili $ 1, ecc.)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top