2012-02-12 4 views
0

Je reçois un texte au format html. Je veux limiter les URL de la balise d'ancrage à mon domaine en remplaçant les anciens liens par "xxx" (ou smth 'else).
Entrée: "<a href='otherdomain'>text</a>"
Sortie: "xxx"
J'utilise regexp pour y parvenir si je suis un peu coincé ici:Regex Retirer le lien vers un autre nom de domaine

$pattern ='/<a.*href=[\'|\"]http.?:\/\/[^mydomain.*\"\']*[\'|\"].*<\/a>/i'; 
$replace ='xxx'; 
echo preg_replace($pattern, $replace, $string); 

Quel est le problème ici?

+0

S'il s'agit d'une entrée d'utilisateur que vous voulez nettoyer, vous devrez également gérer des guillemets d'attribut absents ou un masquage d'entité HTML. Une regex n'atteindra donc que les cas communs; ce n'est pas adapté comme filtre fiable. (Sans effort désordonné qui est.) – mario

+0

duplication possible de [Comment analyser et traiter le code HTML avec PHP?] (Http://stackoverflow.com/questions/3577641/how-to-parse-and-process-html-with- php) – Gordon

+0

@Gordon: Je pense qu'il ne sera pas facile de l'analyser car je reçois la balise dans le cadre d'une chaîne qui a déjà passé un filtre – lvil

Répondre

2

Lorsque vous [^mydomain.*\"\'] vous disent « correspond à tout caractère sauf un littéral 'm', 'y', 'd', 'o', ..., '', '*', etc.

Essayez quelque chose comme:

#<a [^>]*\bhref=(['"])http.?://((?!mydomain)[^'"])+\1 *>.*?</a>#i 

notes:

  • Je retournai votre a.*href-a [^>]*\bhref pour vous assurer que le « a » et « href » sont des mots entiers et que l'expression rationnelle ne correspond pas à sur plusieurs tags
  • J'ai changé le délimiteur regex à « # » au lieu de «/» de sorte que vous ne devez pas échapper à la / plus
  • Notez le ((?!mydomain)[^'"])+. Cela signifie « match de [^ ' « ] + qui n'est pas myDomain ». Le (?! est appelé
  • négatif look-ahead.
  • Notez le \1. Cela fait en sorte que la marque de devis de clôture pour l'URL est la même comme la marque de citation d'ouverture (voir hwo la première série de crochets capture le ['"]?). vous seriez probablement bien sans elle si vous préférions.

pour PHP (mis à jour parce que je mélange toujours quand antislashs doivent être échappé en PHP - voir le commentaire @ GlitchMr ci-dessous):

$pattern = '#<a [^>]*\bhref=([\'"])http.?://((?!mydomain)[^\'"])+\1 *>.*?</a>#i'; 

Voir dans l'action here, où vous pouvez le modifier à vos fins.

+0

Merci. Cela fonctionne parfaitement. Pourriez-vous s'il vous plaît expliquer comment vous réalisez la correspondance des caractères avant et après mydomain? Comme "sub.mydomain.com/page1"? – lvil

+0

Si vous essayez de modifier l'une des URL en "sub.mydomain.com/page1" dans le lien vers l'exemple interactif que j'ai posté, vous verrez que cela ne correspond pas non plus. Ou voulez-vous * faire correspondre "sub.mydomain.com/page1" mais pas "mydomain.com"? –

+0

Tout va bien, je voulais juste savoir comment ça marche. – lvil

1

(bien que n'y a aucune raison de ne pas expliquer quelque chose.)

Si vous voulez faire correspondre « tout sauf », alors vous voulez généralement d'utiliser une affirmation; un negative lookahead assertion dans votre cas:

(?!mydomain\.com).*? 

Cela correspond .*? quoi que ce soit, mais la valeur refusée qui la précède.

Veuillez également prendre note que:

  • Il devrait être [\"\'] et non [\'|\"]. Le signe alternatif n'a aucune signification dans les classes de caractères.
  • .* doit généralement être .*? pour ne pas correspondre trop largement.
  • Et [^>]* est l'idiome commun à correspondre dans les balises.
  • Vous pouvez utiliser d'autres délimiteurs #<a...*>#i à la place de / pour éviter les fuites.
0

[] est l'opérateur de caractère dans l'ensemble. Votre modèle serait beaucoup plus compréhensible que

$pattern ='!<a\s.*?\shref\s*=\s*([\'"])https?:://mydomain.*?\1.*?</a>!is'; 

Note:

  • J'ai des espaces Délimité les jetons
  • troqué le regexp citant char éviter le \/
  • Utiliser une référence arrière pour faire correspondre les citations.
2

Voici une partie du code que j'utilise. Il utilise une fonction utilisateur pour modifier le texte extrait par l'expression régulière. Bonne chance :)

class RedirectLinks { 
    /** 
    * Callback used by convert_external_links_to_internal on each url found 
    * 
    * @param array $matches 
    * @return string 
    */ 
    public static function urlMatchCallback($matches) 
    { 
     if (stripos($matches[1], 'http://') === false || 
      stripos($matches[1], 'example.com') !== false 
      ) { 
      return $matches[0]; // do not modify 
     } 
     // encrypt url for redirection   
     $sURL = $matches[1]; 
     return "href=\"#\" onclick=\"showmessage('$sURL');\""; 
    } 

    /** 
    * Converts external links in text to internal ones 
    * 
    * @param string $str - text 
    * @return the processed text 
    */ 
    public static function convertExternalLinksToInternal($str) { 
     // convert external links to internal redirections 
     $str = preg_replace_callback("/href=\"([^\"]*)\"/is", 'RedirectLinks::urlMatchCallback', $str); 

     return $str;  
    } 
} 
Questions connexes