2009-05-19 6 views
1

C'est plus une question de puzzle pour ma curiosité qu'autre chose. Je suis à la recherche d'une seule substitution d'expression régulière qui convertira les esperluettes échappées en entités en esperluettes non échappées uniquement dans les attributs href d'un fichier html. Par exemple:Expression simple perl pour supprimer les esperluettes échappées de l'intérieur des attributs href mais pas ailleurs

<a href="http://example.com/index.html?foo=bar&amp;baz=qux&amp;frotz=frobnitz"> 
Me, myself &amp; I</a> 

se convertiraient:

<a href="http://example.com/index.html?foo=bar&baz=qux&frotz=frobnitz"> 
Me, myself &amp; I</a> 

Maintenant, je peux le faire dans plusieurs déclarations, mais je suis curieux de savoir si les gourous de regex perl peuvent le faire en un.

Le plus proche que je suis venu jusqu'ici est la regex suivante qui ne fonctionne pas parce que lookbehinds ne peut pas être de longueur variable. Bien sûr, cela pourrait ne pas fonctionner même s'ils étaient autorisés, je ne suis pas sûr.

s/(?<=href=".*?)&amp;(?=.*?")/&/g; 

Merci.

Répondre

3

Adapter approximation:

while (s/(?<=href=")([^"]*?)&amp;/$1&/) {} 

Ceci est un tricheur; mais c'est une seule regex. La partie clé est le balayage non gourmand pour les caractères qui ne sont pas un guillemet double de fermeture suivi de la chaîne &amp;. L'autre observation à faire est que, compte tenu de l'entrée:

<a href="http://example.com/index.html?x=y&amp;amp;amp;y=z"> 

Vous sortirez:

<a href="http://example.com/index.html?x=y&y=z"> 

Vous devez décider si ce qui compte. La difficulté avec toute solution non-itérative est qu'une fois que vous avez lu le 'href="' dans le premier match, vous ne le verrez pas à nouveau pour les correspondances suivantes.

+0

Jonathan, j'aime ta réponse. J'arrivais avec une regex similaire quand je jouais avec le problème mais je ne pensais pas le laisser tomber dans une boucle. Je suis toujours curieux mais s'il y a un moyen avec juste une seule regex. Merci! –

1

N'essayez pas d'analyser des langues non régulières avec des expressions régulières. Obtenez un analyseur HTML du CPAN, puis opérez uniquement sur l'élément dont vous avez besoin.

+0

Mon but ici est juste d'apprendre si c'est possible. Je ne suis pas si préoccupé par la façon * correcte * de travailler avec HTML. Le HTML est vraiment juste pour l'amour par exemple. J'apprécie votre réponse cependant. –

+0

@hrwl considérez ceci comme une leçon importante: une expression rationnelle n'est pas appropriée pour l'analyse HTML. Vous n'apprenez pas à utiliser un tournevis en utilisant des clous d'entraînement. –

+1

Je dirais plus probablement que la leçon est d'utiliser des exemples plus abstraits. Le but était de ne jamais apprendre à analyser le HTML. –

2

Ce regex fera ce que vous voulez dans une seule ligne de code Perl, sans inefficace en boucle (ce qui rend l'expression régulière commence dès le début à chaque fois) ou lookbehind:

s/((href="|\G)[^"]*?&)amp;/$1/g; 

L'astuce est utiliser \ G pour que l'expression rationnelle "se souvienne" qu'elle se trouvait dans un attribut href.

Cette regex remplace également correctement & amp; amp; avec & amp;

La seule imperfection est que si & se produit au tout début de la chaîne sujet, il sera également remplacé. Si vous voulez éviter cela, utilisez:

s/((href="|\G(?!\A))[^"]*?&)amp;/$1/g; 
1

OK. Tout d'abord - l'ampli &; dans hrefs est parfaitement bien, donc je ne comprends pas pourquoi vous voulez le changer - en fait html avec & en hrefs ne serait pas valide!

Deuxièmement - si vous en avez besoin pour quelque chose - vous devriez vraiment utiliser un HTML Parser sensible.

Troisième ce que vous voulez peut être fait assez facilement, mais pas vraiment bien:

s{href="([^"]*)"}{my $q=$1; $q =~ s/\&amp;/&/g; 'href="' . $q . '"'}eg; 

Mais, s'il vous plaît: le fait qu'il est techniquement possible ne signifie pas que vous devez l'utiliser.

Questions connexes