485 votes

Comment remplacer les URL simples par des liens?

J'utilise la fonction ci-dessous pour faire correspondre les URL d'un texte donné et les remplacer par des liens HTML. L'expression régulière fonctionne très bien, mais actuellement je ne fais que remplacer le premier match.

Comment puis-je remplacer toutes les URL? Je suppose que je devrais utiliser la commande exec , mais je n'ai pas vraiment compris comment le faire.

 function replaceURLWithHTMLLinks(text) {
    var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/i;
    return text.replace(exp,"<a href='$1'>$1</a>"); 
}
 

392voto

Dan Dascalescu Points 8165

Tout d'abord, rouler votre propre regexp pour analyser les Url est une idée terrible. Vous devez imaginer que c'est un problème assez commun que quelqu'un a écrit, d'une mise au point et testé une bibliothèque pour elle, selon la Rfc. Les uri sont complexes - découvrez le code pour analyser les URL dans Node.js) et la page de Wikipedia sur les modèles d'URI.

Il y a une tonne de bord des cas quand il s'agit de l'analyse d'Url: noms de domaine international, réel (.museum) vs inexistante (.etc) Tld, bizarre ponctuation, y compris les parenthèses, ponctuation à la fin de l'URL, IPV6 noms d'hôtes etc.

J'ai regardé une tonne de bibliothèques, et ceux qui étaient mérite d'être étudié tous ont leurs inconvénients:

  • Ben Alman du linkify n'a pas été entretenu depuis 2009.
  • Soapbox de jQuery linkify a semblent des efforts sérieux de mettre en elle, mais c'est un peu exagéré dans le tissage de jQuery dans ce qui est essentiellement un caractère purement JavaScript problème
  • Django urlize ne gère pas les Tld correctement. Voici l'officiel de la liste de validité Tld
  • autolink-js ne serait pas en mesure de détecter "www.google.com" sans http://, il n'est donc pas tout à fait adapté pour autolinking "casual Url" (sans jeu de protocole) trouvée en texte clair.

Autolinker.js est la seule bibliothèque que j'ai trouvé jusqu'à présent que des listes de caractéristiques (par exemple, "gèrent correctement les entrées HTML. L'utilitaire va pas changer le href d'attribut à l'intérieur de l'ancre () balises"). Je vais être à la recherche d'plus.

Si vous insistez sur une expression régulière, la plus complète est l' URL de la regexp de Composant, bien qu'il faussement détecter certains inexistante deux lettres Tld en le regardant.

287voto

Sam Hasler Points 10253

Remplacer les Url avec des liens (Réponse à la problématique Générale)

L'expression régulière dans la question manque a beaucoup de cas de bord. Lors de la détection d'Url, il est toujours préférable d'utiliser une bibliothèque spécialisée, qui gère les noms de domaines internationaux, les nouveaux Tld comme .museum, les parenthèses et les autres signes de ponctuation à l'intérieur et à la fin de l'URL, et de nombreux autres cas de bord. Voir le Jeff Atwood blog post Le Problème Avec les Url pour une explication de certains des autres problèmes.

Le meilleur résumé de l'URL correspondant à des bibliothèques est en Dan Dascalescu Réponse +100
(Février 2014)


"Faire une expression régulière remplacer plus de un match" (Réponse à la problématique spécifique)

Ajouter un "g" à la fin de l'expression régulière pour permettre d'appariement globale:

/ig;

Mais qui ne résout le problème dans la question " d'où l'expression régulière était seulement le remplacement du premier match. N'utilisez pas ce code.

172voto

cloud8421 Points 709

J'ai apporté quelques petites modifications au code de Travis (juste pour éviter toute redéclaration inutile - mais cela fonctionne très bien pour mes besoins, donc bon travail!):

 function linkify(inputText) {
    var replacedText, replacePattern1, replacePattern2, replacePattern3;

    //URLs starting with http://, https://, or ftp://
    replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
    replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank">$1</a>');

    //URLs starting with "www." (without // before it, or it'd re-link the ones done above).
    replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
    replacedText = replacedText.replace(replacePattern2, '$1<a href="http://$2" target="_blank">$2</a>');

    //Change email addresses to mailto:: links.
    replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
    replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');

    return replacedText;
}
 

76voto

Roshambo Points 1046

Quelques optimisations ont été apportées au code Linkify() de Travis ci-dessus. J'ai également corrigé un bug où les adresses e-mail avec des formats de type sous-domaine ne correspondraient pas (par exemple: exemple@domaine.fr).

De plus, j'ai changé l'implémentation pour prototyper la classe String afin que les éléments puissent être appariés comme ceci:

 var text = 'address@example.com';
text.linkify();

'http://stackoverflow.com/'.linkify();
 

Quoi qu'il en soit, voici le script:

 if(!String.linkify) {
    String.prototype.linkify = function() {

        // http://, https://, ftp://
        var urlPattern = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim;

        // www. sans http:// or https://
        var pseudoUrlPattern = /(^|[^\/])(www\.[\S]+(\b|$))/gim;

        // Email addresses
        var emailAddressPattern = /\w+@[a-zA-Z_]+?(?:\.[a-zA-Z]{2,6})+/gim;

        return this
            .replace(urlPattern, '<a href="$&">$&</a>')
            .replace(pseudoUrlPattern, '$1<a href="http://$2">$2</a>')
            .replace(emailAddressPattern, '<a href="mailto:$&">$&</a>');
    };
}
 

27voto

Travis Points 267

Merci, cela a été très utile. Je voulais aussi quelque chose qui permettrait de relier les choses qui ressemblait à une URL, comme une exigence de base, il avait un lien de quelque chose comme www.yahoo.com même si le protocole http:// préfixe n'était pas présent. Donc en gros, si le "www" est présent, il va le lier et d'assumer c'est http://. Je voulais aussi e-mails à tourner dans les liens mailto:. EXEMPLE: www.yahoo.com serait converti à www.yahoo.com

Voici le code que j'ai fini avec (combinaison de code à partir de cette page, et d'autres trucs que j'ai trouvé en ligne, et d'autres trucs que j'ai fait sur mon propre):

function Linkify(inputText) {
    //URLs starting with http://, https://, or ftp://
    var replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
    var replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank">$1</a>');

    //URLs starting with www. (without // before it, or it'd re-link the ones done above)
    var replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
    var replacedText = replacedText.replace(replacePattern2, '$1<a href="http://$2" target="_blank">$2</a>');

    //Change email addresses to mailto:: links
    var replacePattern3 = /(\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,6})/gim;
    var replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');

    return replacedText
}

Dans le 2ème remplacer, le (^|[^/]) est un remplacement www.whatever.com si c'est pas déjà le préfixe // -- afin d'éviter une double liaison si une URL a déjà été liée à la première remplacer. Aussi, il est possible que www.whatever.com peut-être au début de la chaîne, qui est la première condition "ou" dans la partie de l'expression régulière.

Ceci pourrait être intégré comme un plugin jQuery que Jesse P illustré ci-dessus-mais j'ai souhaité spécifiquement une fonction régulière qui n'agissait pas sur un élément du DOM, parce que je prends tout le texte que j'ai et puis l'ajouter au DOM, et je veux que le texte soit "linkified" avant que je ajouter, donc j'ai passer le texte par le biais de cette fonction. Fonctionne très bien.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X