2009-06-27 18 views
5

Wie kann ich Perl regexps verwenden, um alle URLs einer bestimmten Domäne (mit möglicherweise variablen Subdomains) mit einer bestimmten Erweiterung aus reinem Text zu extrahieren? Ich habe versucht:Verwenden von Regex zum Extrahieren von URLs aus reinem Text mit 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"; 
} 

Es schlägt fehl, schrecklich und gibt mir:

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

Ich dachte, das würde nicht passieren, weil ich .*? verwende, das sollte nicht gierig sein und geben Sie mir die kleinste Spiel. Kann mir jemand sagen, was ich falsch mache? (Ich möchte nicht etwas uber-Komplex, in Dosen regexp URLs zu überprüfen, ich möchte wissen, was ich tue, falsch, so kann ich daraus lernen.)

Antwort

5

Besuchen CPAN: Regexp::Common::URI

bearbeiten: Selbst wenn Sie keinen regulären Ausdruck in der Liste haben möchten, kann es Ihnen helfen, die Quelle eines getesteten Moduls zu betrachten, das funktioniert.

Wenn Sie URLs finden möchten, die einer bestimmten Zeichenfolge entsprechen, können Sie dieses Modul einfach dazu verwenden.

#!/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 wurde speziell entwickelt, um dieses Problem zu lösen. Es wird alle URIs finden und Sie können sie dann filtern. Es hat ein paar Heuristiken, um Dinge wie nachlaufende Interpunktion zu behandeln.

UPDATE: Kürzlich aktualisiert, um Unicode zu behandeln.

0

ich dachte, das sollte nicht passieren, weil ich benutze. *? die sollten nicht gierig sein und gib mir das kleinste Spiel

Es tut, aber es gibt Ihnen das kleinste Spiel geht rechts. Ausgehend von der ersten http und nach rechts gehend, ist das die kleinste Übereinstimmung.

Bitte beachten Sie, dass Sie für die Zukunft keine Schrägstriche abbrechen müssen, da Sie keine Schrägstriche als Trennzeichen verwenden müssen. Und Sie müssen auch nicht dem Doppelpunkt entkommen. Das nächste Mal, dies nur tun:

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

oder

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

oder

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

oder einem der vielen anderen Zeichen finden Sie in der Dokumentation perlre.

1

URLs dürfen keine Leerzeichen enthalten, also statt. *? Sie sollten \ S *? für null oder mehr Leerzeichen verwenden.

+0

[RFC 3986 Anhang C] (http://tools.ietf.org/html/rfc3986#appendix-C) behandelt die speziellen Probleme beim Extrahieren von URIs, einschließlich Fälle, in denen Whitespace zulässig ist. "In einigen Fällen müssen möglicherweise zusätzliche Leerzeichen (Leerzeichen, Zeilenumbrüche, Tabulatoren usw.) hinzugefügt werden, um einen langen URI über mehrere Zeilen hinweg zu trennen. Der Leerraum sollte ignoriert werden, wenn der URI extrahiert wird." Und "aus Gründen der Robustheit sollte Software, die benutzer-typisierte URI akzeptiert, versuchen, sowohl Delimiter als auch eingebettete Leerzeichen zu erkennen und zu entfernen." Aus Erfahrung ist dies jedoch schwierig. – Schwern

0

hier ein regex ist (hoffentlich) bekommen | Auszug | erhalten alle URLs aus string | Textdatei, die für mich zu funktionieren scheint:

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

...oder in einem Beispiel:

$ 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 

Für meine Noob Referenz, hier ist die Debug-Version des gleichen Befehl über:

$ 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"} }' 

Die Regex passt auf http(s):// - und verwendet Leerzeichen, " und ) als " "Charaktere" verlassen; verwendet dann positive lookahead, um zunächst eine "Exit" auf "http" Literalgruppe zu verursachen (wenn eine Übereinstimmung bereits in Arbeit ist); Da jedoch auch das letzte Zeichen der vorherigen Übereinstimmung "gegessen" wird, wird die Vorausschau-Übereinstimmung hier um ein Zeichen nach "ttp:" verschoben.

Einige nützliche Seiten:

Hoffnung hilft dieses jemand,
012.351.Prost!

EDIT: Ups, findet nur etwa URI::Find::Simple - search.cpan.org, scheint das gleiche zu tun (über regex - Getting the website title from a link in a string)

2

ich verwendet habe Code die Links zu extrahieren, die mit spezifischer Verlängerung enden
wie * .htm, * .html, * .gif, * .jpeg. Hinweis: In diesem Skript wird die Erweiterung * .html zuerst geschrieben und dann * .htm, weil beide "htm" gemeinsam haben. Diese Art von Änderungen sollte also sorgfältig durchgeführt werden.

Eingabe: Dateiname mit Links und Name der Ausgabedatei, in der die Ergebnisse gespeichert werden.
Ausgabe: Wird in der Ausgabedatei gespeichert. hier

-Code lautet:

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

Ausgabe der Zeichenfolge ist hier:

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

Warum verwenden Sie nicht '(html? | Gif | jpe? G)' anstelle von '(html | htm | gif | jpeg | jpg)'? –

+0

@BradGilbert: ja das ist besser :) – Pushpendra

+0

Perfekt, perfekt! –

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

Diese Regex für mich gearbeitet

+0

Ein wenig mehr Kontext und/oder Erklärung wäre nett. –

Verwandte Themen