2010-12-09 6 views
1

J'ai deux questions à propos de Regexp::Common qw/URI/et Regex en Perl. J'utilise Regexp::Common qw/URI/ pour analyser l'URI dans les chaînes et les supprimer. Mais j'ai une erreur quand un URI est entre parenthèses.En Perl, comment extraire correctement les URL entre parenthèses?

Par exemple: (http://www.example.com)

L'erreur est causée par «) », et quand il essaie d'analyser l'URI, le crash de l'application. J'ai donc pensé que deux corrections:

  • faire un simple (ou je pensais) qui écrit un espace entre parenthèses et ) caractères
  • Le Regexp::Common qw/URI/ a une fonction qui mettent en œuvre une solution.

Dans mon code, j'ai essayé d'implémenter le Regex mais l'application se bloque. Le code que j'ai essayé est le suivant:

use strict; 

use Regexp::Common qw/URI/; 
my $str = "Hello!!, I love (http://www.example.com)"; 
while ($str =~ m/\)/){ 
       $str =~ s/\)/ \)/; 
     } 
my ($uri) = $str =~ /$RE{URI}{-keep}/; 
print "$uri\n"; 
print $str; 

La sortie que je veux est: (http://www.example.com)

Je ne suis pas sûr, mais je pense que le problème est dans $str =~ s/\)/ \)/;

BTW, J'ai une question à propos de Regexp :: Common qw/URI /. J'ai deux types de chaîne:

  1. ablalbalblalblalbal http://www.example.com
  2. asfasdfasdf http://www.example.com aasdfasdfasdf

Je veux supprimer l'URI si elle est le dernier composant (et enregistrez). Et sinon, enregistrez-le sans le supprimer du texte.

+0

Vous devriez lire les conseils sur la façon de formater votre message. Vous n'avez pas besoin d'entrer des liens en direct pour pouvoir inclure un ensemble d'URL dans votre message. Et, pas besoin d'insérer '
' dans le code. –

Répondre

0
my $str = "Hello!!, I love (GOOGLE)"; 
while ($str =~ m/)/){ 
    $str =~ s/)/)/; 
} 

Votre programme entre dans une boucle infinie à ce stade. Pour voir pourquoi, essayez d'imprimer la valeur de $ str à chaque fois autour de la boucle.

my $str = "Hello!!, I love (GOOGLE)"; 
while ($str =~ m/)/){ 
    $str =~ s/)/)/; 
    print $str, "\n"; 
} 

La première fois qu'il affiche "Hello !!, I love (GOOGLE)". La condition de boucle while est ensuite évaluée à nouveau. Votre chaîne correspond toujours à votre expression régulière (elle contient toujours une parenthèse fermante), le remplacement est donc exécuté à nouveau et cette fois-ci, elle affiche "Hello !!, I love (GOOGLE)" avec deux espaces.

Et ainsi de suite. À chaque tour de la boucle, un autre espace est ajouté, mais chaque fois que vous avez encore une parenthèse fermante, une autre substitution est exécutée.

La solution la plus simple que je puisse voir est de ne faire correspondre la parenthèse fermante que si elle est précédée d'un caractère non-espace (en utilisant \ S).

my $str = "Hello!!, I love (GOOGLE)"; 
while ($str =~ m/\S)/){ 
    $str =~ s/)/)/; 
    print $str, "\n"; 
} 

Dans ce cas, la boucle n'est exécutée qu'une seule fois.

2

Vous n'avez pas besoin de tester d'abord une correspondance pour pouvoir utiliser correctement l'opérateur s///: Si la chaîne ne correspond pas au modèle de recherche, elle ne fera rien.

#!/usr/bin/perl 

use strict; use warnings; 

my $str = "Hello!!, I love (GOOGLE)"; 
$str =~ s/\)/)/g; 

print "$str\n"; 

Le problème général de la détection correcte des URL dans le texte est sujet aux erreurs. Voir par exemple Jeff's thoughts on this.

0

Pourquoi ne pas simplement inclure les parenthèses dans la recherche? Si les URL seront toujours entre crochets, alors quelque chose comme ceci:

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

my $str = "Hello!!, I love (http://www.google.com)"; 
my ($uri) = $str =~/\(($RE{URI}) \) /x; 
print "$uri\n"; 

Le regex de Regex :: Common peut être utilisé dans le cadre d'un regex plus, il ne doit pas être utilisé seul. J'ai aussi utilisé le modificateur 'x' sur la regex pour autoriser les espaces afin que vous puissiez voir plus clairement ce qui se passe - les crochets avec les barres obliques inverses sont traités comme des caractères à associer, ceux sans définir ce qui doit être apparié (vraisemblablement {-keep} - Je n'ai jamais utilisé ça auparavant.

Vous pouvez également les supports en option, avec quelque chose comme:

/ (?: \(($RE{URI}) \) | ($RE{URI}))/

bien qui se traduirait par deux variables match, un non défini - donc quelque chose comme suit serait nécessaire:

my $uri = $1 || $2 || die "Didn't match a URL!"; 

Il y a probablement une meilleure façon de le faire, et si vous n'êtes pas préoccupé par les parenthèses correspondantes, vous pouvez simplement rendre les parenthèses facultatives (via un '?') Dans la première regex ...

Pour répondre à votre deuxième question concernant seulement les URLs correspondantes à la fin de la ligne - jetez un coup d'œil aux 'ancres' de Regex qui peuvent forcer une correspondance avec le début ou la fin d'une ligne:^et $ (ou \ A et \ Z si tu préfères). par exemple. correspondant à une URL à la fin d'une ligne uniquement:

/$RE{URI}\Z/ 
Questions connexes