2009-06-27 6 views
5

Come posso usare le espressioni regolari di Perl per estrarre tutti gli URL di un dominio specifico (con sottodomini probabilmente variabili) con un'estensione specifica da testo normale? Ho provato:Uso della regex per estrarre gli URL dal testo normale con Perl

my $stuff = 'omg http://fail-o-tron.com/bleh omg omg omg omg omg http://homepage.com/woot.gif dfgdfg http://shomepage.com/woot.gif aaa'; 
while($stuff =~ m/(http\:\/\/.*?homepage.com\/.*?\.gif)/gmsi) 
{ 
print $1."\n"; 
} 

fallisce terribilmente e mi dà:

http://fail-o-tron.com/bleh omg omg omg omg omg http://homepage.com/woot.gif 
http://shomepage.com/woot.gif 

ho pensato che non sarebbe accaduto perché sto usando .*?, che dovrebbe essere non-avidi e mi darà la più piccola incontro. Qualcuno può dirmi cosa sto facendo di sbagliato? (Non voglio un po 'uber-complesso, regexp in scatola per convalidare gli URL, voglio sapere che cosa sto facendo male così posso imparare da esso.)

risposta

5

Visita CPAN: Regexp::Common::URI

Edit: Anche se non vuoi un'espressione regolare in scatola, può aiutarti a vedere la fonte di un modulo testato che funziona.

Se si desidera trovare gli URL che corrispondono a una determinata stringa, è possibile utilizzare facilmente questo modulo per farlo.

#!/usr/bin/env perl 
use strict; 
use warnings; 
use Regexp::Common qw/URI/; 

while (<>) { 
    if (m/$RE{URI}{HTTP}{-keep}/) { 
    print $_ if $1 =~ m/what-you-want/; 
    } 
} 
16

URI::Find è specificamente progettato per risolvere questo problema. Troverà tutti gli URI e quindi potrai filtrarli. Ha alcune euristiche per gestire cose come la punteggiatura finale.

AGGIORNAMENTO: aggiornato di recente per gestire Unicode.

0

ho pensato che non dovrebbe accadere perché sto usando. *? che dovrebbe essere non-avidi e mi danno la più piccola partita

Lo fa, ma ti dà la più piccola partita in corso destra. A partire dal primo http e andando a destra, questa è la partita più piccola.

Nota per il futuro, non è necessario sfuggire alle barre, perché non è necessario utilizzare le barre come separatore. E non devi nemmeno sfuggire al colon. La prossima volta basta fare questo:

m|(http://.*?homepage.com\/.*?\.gif)| 

o

m#(http://.*?homepage.com\/.*?\.gif)# 

o

m<(http://.*?homepage.com\/.*?\.gif)> 

o uno dei tanti altri personaggi, consultare la documentazione perlre.

1

Gli URL non possono contenere spazi, quindi anziché. *? dovresti usare \ S * ?, per zero o più caratteri non spaziali.

+0

[RFC 3986 Appendice C] (http://tools.ietf.org/html/rfc3986#appendix-C) discute i problemi speciali dell'estrazione degli URI, compresi i casi in cui lo spazio bianco è ammissibile. "In alcuni casi, potrebbe essere necessario aggiungere spazi bianchi extra (spazi, interruzioni di riga, tabulazioni, ecc.) Per rompere un URI lungo attraverso le linee. Gli spazi bianchi devono essere ignorati quando viene estratto l'URI." E "per la robustezza, il software che accetta l'URI tipizzato dall'utente dovrebbe tentare di riconoscere e rimuovere entrambi i delimitatori e gli spazi bianchi incorporati". Detto questo, per esperienza, questo è difficile. – Schwern

0

Ecco una regex per (si spera) ottenere | estratto | ottenere tutti gli URL da string | file di testo, che sembra funzionare per me:

m,(http.*?://([^\s)\"](?!ttp:))+),g 

...o in un esempio:

$ echo -e "\n\na blahlah blah:http://www.abc.com/dss.htm?a=1&p=2#chk - blahblah \"https://poi.com/a%20b\"; (http://bbb.comhttp://roch.com/abc) \n" | perl -ne 'while (my $string = <>) { print "$string\n"; while ($string =~ m,(http.*?://([^\s)\"](?!ttp:))+),g) {print "$&\n"} }' 


a blahlah blah:http://www.abc.com/dss.htm?a=1&p=2#chk - blahblah "https://poi.com/a%20b"; (http://bbb.comhttp://roch.com/abc) 

http://www.abc.com/dss.htm?a=1&p=2#chk 
https://poi.com/a%20b 
http://bbb.com 
http://roch.com/abc 

Per il mio riferimento niubbo, ecco la versione di debug dello stesso comando precedente:

$ echo -e "\n\na blahlah blah:http://www.abc.com/dss.htm?a=1&p=2#chk - blahblah \"https://poi.com/a%20b\"; (http://bbb.comhttp://roch.com/abc) \n" | perl -dne 'use re "debug" ; while (my $string = <>) { print "$string\n"; while ($string =~ m,(http.*?://([^\s)\"](?!ttp:))+),g) {print "$&\n"} }' 

la regex sul http(s):// - e utilizza gli spazi bianchi, " e ) come " uscita "caratteri; quindi utilizza positive lookahead per, inizialmente, causa un "exit" sul gruppo "http" letterale (se una corrispondenza è già in corso); tuttavia, poiché anche "mangia" l'ultimo carattere della precedente corrispondenza, qui la corrispondenza lookahead viene spostata di un carattere in avanti a "ttp:".

Alcune pagine utili:

Spero che questo aiuti qualcuno,
012.351.Saluti!

EDIT: Ups, appena trovato su URI::Find::Simple - search.cpan.org, sembra fare la stessa cosa (via regex - Getting the website title from a link in a string)

2

Ho usato seguente codice per estrarre i collegamenti che si conclude con specifici estensione
come * .htm, * .html, * .gif, * .jpeg. Nota: In questa estensione di script * .html viene scritto prima e quindi * .htm perché entrambi hanno "htm" in comune. Quindi questo tipo di cambiamenti dovrebbe essere fatto con attenzione.

Ingresso: Nome file con collegamenti e nome file di output in cui verranno salvati i risultati.
Uscita: Verrà salvato nel file di output.

Codice va qui:

use strict; 
use warnings; 

if ($#ARGV != 1) { 
print 
"Incorrect number of arguments.\nArguments: Text_LinkFile, Output_File\n"; 
die $!; 
} 
open FILE_LINKS, $ARGV[0] or die $!; 
open FILE_RESULT, ">$ARGV[1]" or die $!; 

my @Links; 
foreach (<FILE_LINKS>) { 
    my @tempArray; 
    my (@Matches) =($_ =~ m/((https?|ftp):\/\/[^\s]+\.(html?|gif|jpe?g))/g); 
    for (my $i = 0 ; $i < $#Matches ; $i += 3) { 
     push(@Links, $Matches[$i]); 
     } 
    } 
print FILE_RESULT join("\n", @Links); 

uscita della stringa è qui:

http://homepage.com/woot.gif 
http://shomepage.com/woot.gif 
+0

Perché non usi '(html? | Gif | jpe? G)' invece di '(html | htm | gif | jpeg | jpg)'? –

+0

@BradGilbert: sì è meglio :) – Pushpendra

+0

Perfetto, perfetto! –

1
https?\:\/\/[^\s]+[\/\w] 

Questa espressione regolare ha funzionato per me

+0

Un po 'più di contesto e/o spiegazione sarebbe bello. –

Problemi correlati