2010-04-02 11 views
2

J'ai besoin de l'expression rationnelle Perl pour analyser l'entrée de texte brut et convertir tous les liens en liens HREF HTML valides. J'ai essayé 10 versions différentes que j'ai trouvées sur le web mais aucune d'entre elles ne semblait fonctionner correctement. J'ai également testé d'autres solutions publiées sur StackOverflow, mais aucune ne semble fonctionner. La bonne solution devrait être en mesure de trouver une URL dans l'entrée de texte brut et le convertir en:Comment puis-je extraire des URL à partir de texte brut avec Perl?

<a href="$1">$1</a> 

Quelques cas d'autres expressions régulières, j'ai essayé ne pas traiter comprennent correctement:

  1. URL à la fin d'une ligne qui sont suivis par des retours
  2. URL qui comprenaient des points d'interrogation
  3. URL commençant par « https »

J'espère qu'un autre type de Perl aura déjà une expression régulière à utiliser pour ce partage. Merci d'avance pour votre aide!

+0

regex est notoirement mauvaise manipulation à forme équilibrée. Puisque les URL sont basées sur une forme équilibrée, ce n'est pas la meilleure application pour regex. Je recommande d'utiliser une machine d'état à la place – tzenes

+3

Qui vous a dit que les URL sont équilibrées? –

+1

Les URL ne sont définitivement pas équilibrées. Cela ne veut pas dire que c'est forcément facile de bien les faire correspondre à une regex, bien sûr. –

Répondre

2

Quand j'ai essayé URI::Find::Schemeless avec le texte suivant:

Here is a URL and one bare URL with 
https: https://www.example.com and another with a query 
http://example.org/?test=one&another=2 and another with parentheses 
http://example.org/(9.3) 

Another one that appears in quotation marks "http://www.example.net/s=1;q=5" 
etc. A link to an ftp site: ftp://[email protected]/test/me 
How about one without a protocol www.example.com?

il foiré http://example.org/(9.3). Alors, je suis venu avec ce qui suit à l'aide de Regexp::Common:

#!/usr/bin/perl 

use strict; use warnings; 
use CGI 'escapeHTML'; 
use Regexp::Common qw/URI/; 
use URI::Find::Schemeless; 

my $heuristic = URI::Find::Schemeless->schemeless_uri_re; 

my $pattern = qr{ 
    $RE{URI}{HTTP}{-scheme=>'https?'} | 
    $RE{URI}{FTP} | 
    $heuristic 
}x; 

local $/ = ''; 

while (my $par = <DATA>) { 
    chomp $par; 
    $par =~ s/</&lt;/g; 
    $par =~ s/($pattern)/linkify($1) /gex; 
    print "<p>$par</p>\n"; 
} 

sub linkify { 
    my ($str) = @_; 
    $str = "http://$str" unless $str =~ /^[fh]t(?:p|tp)/; 
    $str = escapeHTML($str); 
    sprintf q|<a href="%s">%s</a>|, ($str) x 2; 
} 

Cela a fonctionné pour l'entrée indiquée. Bien sûr, la vie n'est jamais aussi simple que vous pouvez le voir en essayant (http://example.org/(9.3)).

+0

@Sinan - C'était un peu plus compliqué que ce que j'espérais mais finalement c'était la seule solution qui capturait correctement les liens qui manquaient la partie 'http: //' de l'URL –

10

Vous souhaitez URI::Find. Une fois que vous avez extrait les liens, vous devriez être capable de gérer le reste du problème.

La réponse à la question perlfaq9 répond à la question "How do I extract URLs?", soit dit en passant. Il y a beaucoup de bonnes choses dans ces perlfaq. :)

+0

le lien semble être cassé – MadCoder

+0

J'ai tapé le mauvais nom de paquet dans le lien, mais je l'ai fixé. –

4

En plus URI::Find, checkout aussi la grande base de données d'expression régulière: Regexp::Common, il y a un module Regexp::Common::URI qui vous donne quelque chose d'aussi simple que:

my ($uri) = $str =~ /$RE{URI}{-keep}/; 

Si vous voulez différentes pièces (nom d'hôte, les paramètres de la requête, etc.) dans cet uri, voir le doc de Regexp::Common::URI::http pour ce qui est capturé dans l'expression régulière $RE{URI}.

+0

Regex :: Common est un ensemble impressionnant d'outils. Presque toutes les expressions rationnelles auxquelles vous pouvez penser existent déjà. Il est triste que les gens continuent de les réinventer :( –

1

Ici, j'ai posté l'exemple de code en utilisant comment extraire les URL. Ici, il prendra les lignes du stdin. Et il vérifiera si la ligne d'entrée contient un format d'URL valide. Et il vous donnera l'URL

use strict; 
use warnings; 

use Regexp::Common qw /URI/; 

while (1) 
{ 
     #getting the input from stdin. 
     print "Enter the line: \n"; 
     my $line = <>; 
     chomp ($line); #removing the unwanted new line character 
     my ($uri)= $line =~ /$RE{URI}{HTTP}{-keep}/  and print "Contains an HTTP URI.\n"; 
     print "URL : $uri\n" if ($uri); 
} 

Exemple de sortie Je reçois est la suivante

Enter the line: 
http://stackoverflow.com/posts/2565350/ 
Contains an HTTP URI. 
URL : http://stackoverflow.com/posts/2565350/ 
Enter the line: 
this is not valid url line 
Enter the line: 
www.google.com 
Enter the line: 
http:// 
Enter the line: 
http://www.google.com 
Contains an HTTP URI. 
URL : http://www.google.com 
+0

@thillai - Cela ne semble pas fonctionner pour les URL commençant par 'https' ou celles qui ne contiennent pas le 'http: // 'comme votre exemple' www.google.com 'ci-dessus: avez-vous des idées sur la façon de modifier votre implémentation pour gérer ces cas? –