Como substituir URLs simples por links?


453

Estou usando a função abaixo para corresponder a URLs dentro de um determinado texto e substituí-los por links HTML. A expressão regular está funcionando muito bem, mas atualmente estou substituindo apenas a primeira correspondência.

Como posso substituir todo o URL? Acho que deveria estar usando o comando exec , mas realmente não sabia como fazê-lo.

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>"); 
}

Respostas:


350

Primeiro, rolar seu próprio regexp para analisar URLs é uma péssima idéia . Você deve imaginar que este é um problema comum o suficiente para que alguém tenha escrito, depurado e testado uma biblioteca para ele, de acordo com as RFCs . Os URIs são complexos - verifique o código para análise de URL no Node.js e a página da Wikipedia em esquemas de URI .

Existem muitos casos extremos quando se trata de analisar URLs: nomes de domínio internacionais , TLDs reais ( .museum) vs. inexistentes ( .etc), pontuação estranha incluindo parênteses , pontuação no final da URL, nomes de host IPV6 etc.

Eu olhei para uma tonelada de bibliotecas , e há algumas que valem a pena usar, apesar de algumas desvantagens:

Bibliotecas que eu desqualifiquei rapidamente para esta tarefa:

Se você insiste em uma expressão regular, o mais abrangente é o regexp de URL do Component , embora ele detecte falsamente alguns TLDs de duas letras inexistentes olhando para ele.


3
É uma pena que URL regexp from Componentnão seja comentado, alguma explicação do que está fazendo seria útil. Autolinker.jsé comentado muito bem e tem testes. A urlize.jsbiblioteca vinculada à resposta de Vebjorn Ljosa também parece funcional e bem conservada, embora não tenha testes.
Sam Hasler

1
O Regex101.com "explica" automaticamente o regexp, mas boa sorte com isso :) Também encontrei rapidamente um caso de falha com um TLD inválido (mesmo link).
Dan Dascalescu

1
@SamHasler: o Autolinker precisa melhorar na área de TLDs e IDNs. Adicionados alguns testes .
Dan Dascalescu

2
Curioso que ninguém mencionou os esforços de John Gruber em manter um padrão de regex de URL . Não é a única solução / ideal para o problema, mas, de qualquer forma, vale a pena investigar se você está lançando sua própria solução. Só queria adicionar isso como referência.
oelna

2
@DanDascalescu Dê uma olhada neste markdown-it.github.io/linkify-it . Essa biblioteca é focada exatamente em uma tarefa - detectar padrões de links no texto. Mas espero que faça bem. Por exemplo, ele possui suporte unicode correto, incluindo caracteres astrais. E suporta TLDs internacionais.
Vitaly

285

Substituindo URLs por Links (Resposta ao Problema Geral)

A expressão regular na pergunta perde muitos casos extremos. Ao detectar URLs, é sempre melhor usar uma biblioteca especializada que lida com nomes de domínio internacionais, novos TLDs .museum, parênteses e outras pontuações dentro e no final da URL e muitos outros casos extremos. Veja a postagem de Jeff Atwood no blog The Problem With URLs para uma explicação de alguns dos outros problemas.

O melhor resumo das bibliotecas correspondentes a URL está na resposta de Dan Dascalescu+100
(em fevereiro de 2014)


"Fazer uma expressão regular substituir mais de uma correspondência" (resposta ao problema específico)

Adicione um "g" ao final da expressão regular para ativar a correspondência global:

/ig;

Mas isso apenas resolve o problema na pergunta em que a expressão regular estava substituindo apenas a primeira correspondência. Não use esse código.


150

Fiz algumas pequenas modificações no código de Travis (apenas para evitar redeclarações desnecessárias - mas está funcionando muito bem para as minhas necessidades, um ótimo trabalho!):

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;
}

1
como editar esse código para não danificar objetos e iframes incorporados .. (objetos e iframes incorporados do youtube) #
Pradyut Bhattacharya

5
Há um erro no código que corresponde aos endereços de email aqui. [a-zA-Z]{2,6}deve ler algo ao longo das linhas (?:[a-zA-Z]{2,6})+para corresponder a nomes de domínio mais complicados, por exemplo, email@example.co.uk.
Roshambo

1
Eu já tive alguns problemas; primeiro, apenas http: // ou http: // www (sem espaço www até o SO analisa isso errado, aparentemente) criará um link. E links com http: // www. domínio com (sem espaços) criará um link vazio e, em seguida, um com uma marca de fechamento de âncora anexada no campo href.
Alfred

1
E os URLs sem http://ou www? Isso funcionará para esse tipo de URL?
Nathan

2
Tentei editar a postagem original para corrigir o problema mailto, mas preciso adicionar pelo menos 6 caracteres para fazer uma edição. Mas se você alterar esta linha: replacePattern3 = /(\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,6})/gim;com este replacePattern3 = /(\w+@[a-zA-Z_]+?(\.[a-zA-Z]{2,6})+)/gim;que corrige o problema mailto :)
yourdeveloperfriend

70

Fiz algumas otimizações no Linkify()código de Travis acima. Também corrigi um erro em que endereços de email com formatos de subdomínio não correspondiam (por exemplo, exemplo@domínio.com.br).

Além disso, alterei a implementação para criar um protótipo da Stringclasse para que os itens possam ser correspondidos da seguinte maneira:

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

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

Enfim, aqui está o 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>');
    };
}

O melhor na minha opinião, como funções protótipo tornar as coisas muito mais limpo :)
MRVDOG

parece que não funciona com esses endereços de e-mail: info@some-thing.com some.thing@example.com etc ..
Marco Gagliardi

@MarcoGagliardi Good catch. Fixo.
21314 Roshambo

1
Isso não funciona para a string "git clone aaaa@bitbucket.org/ooo/bbb-cc-dd.git ". Ele quebrou a cadeia em pedaços e criou várias âncoras como esta "git clone <a href="https://<a href="mailto:aaaa@bitbucket.org"> aaaa@bitbucket.org </a> / ooo / bbb-cc-dd.git "> https: // <a href="mailto:aaaa@bitbucket.org"> aaaa@bitbucket.org </a> /ooo/bbb-cc-dd.git </a> "
Jebin 29/10/2015

1
Não funciona com +nomes de usuário de email, como foo+bar@domain.com. Corrigi-o com o padrão de email /[\w.+]+@[a-zA-Z_-]+?(?:\.[a-zA-Z]{2,6})+/gim(observe os +primeiros colchetes), mas não sei se isso quebra alguma outra coisa.
dchacke

24

Obrigado, isso foi muito útil. Eu também queria algo que vinculasse coisas que parecessem uma URL - como requisito básico, vincularia algo como www.yahoo.com, mesmo que o prefixo do protocolo http: // não estivesse presente. Então, basicamente, se "www". está presente, ele o vincula e assume que é http: //. Eu também queria que os e-mails se transformassem em mailto: links. EXEMPLO: www.yahoo.com seria convertido em www.yahoo.com

Aqui está o código que eu terminei (combinação de código desta página e outras coisas que encontrei on-line e outras que fiz sozinho):

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
}

Na segunda substituição, a parte (^ | [^ /]) está substituindo apenas www.whatever.com se ainda não tiver sido prefixado por // - para evitar a vinculação dupla se um URL já estiver vinculado na primeira substituição. Além disso, é possível que www.whatever.com esteja no início da string, que é a primeira condição "ou" nessa parte da regex.

Isso poderia ser integrado como um plug-in jQuery, como Jesse P ilustrou acima - mas eu queria especificamente uma função regular que não estivesse atuando em um elemento DOM existente, porque estou pegando o texto que tenho e adicionando-o ao DOM, e Quero que o texto seja "vinculado" antes de adicioná-lo, então passo o texto por essa função. Funciona bem.


1
Há um problema com o segundo padrão, que corresponde a "www.domain.com" simples por si só. O problema existe quando o URL tem algum tipo de referenciador, como: & location = http% 3A% 2F% 2Fwww.amazon.com% 2FNeil-Young% 2Fe% 2FB000APYJWA% 3Fqid% 3D1280679945% 26sr% 3D8-2-ent & tag = tra0c7 -20 & linkCode = ur2 & camp = 1789 & creative = 9325 - nesse caso, o link é vinculado automaticamente novamente. Uma solução rápida é adicionar o caractere "f" após a lista negada que contém "/". Portanto, a expressão é: replacePattern2 = /(^|[^\/f])(www\.[\S]+(\b|$))/gim
Redtopia

O código acima falhará em muitos testes para casos extremos. Ao detectar URLs, é melhor contar com uma biblioteca especializada. Aqui está o porquê .
Dan Dascalescu

2
Eu apenas o executei em uma string em que alguns dos links da web já possuem links href. Nesse caso, ele falha ao atrapalhar os links de trabalho existentes.
AdamJones

17

A identificação de URLs é complicada porque eles geralmente são cercados por sinais de pontuação e porque os usuários frequentemente não usam o formulário completo do URL. Existem muitas funções JavaScript para substituir URLs por hiperlinks, mas não consegui encontrar uma que funcione tão bem quanto o urlizefiltro na estrutura da Web baseada em Python Django. Por isso, portamos a urlizefunção do Django para JavaScript:

https://github.com/ljosa/urlize.js

Um exemplo:

urlize('Go to SO (stackoverflow.com) and ask. <grin>', 
       {nofollow: true, autoescape: true})
=> "Go to SO (<a href="http://stackoverflow.com" rel="nofollow">stackoverflow.com</a>) and ask. &lt;grin&gt;"

O segundo argumento, se verdadeiro, faz rel="nofollow"com que seja inserido. O terceiro argumento, se verdadeiro, escapa caracteres com significado especial em HTML. Veja o arquivo LEIA-ME .


Também funciona com fonte html como: www.web.com <a href =
"https: // github. Com">

@ Paulius: se você definir a opção django_compatiblecomo false, ele lidará com esse caso de uso um pouco melhor.
Vebjorn Ljosa

O Django urlizenão suporta TLDs corretamente (pelo menos não a porta JS no GitHub). Uma biblioteca que lida com TLDs corretamente é o JavaScript Linkify de Ben Alman .
Dan Dascalescu

Suporte para a detecção de URLs com domínios de nível superior adicionais, mesmo quando o URL não inicia com "http" ou "www" foi adicionado.
Vebjorn Ljosa

10

Fiz uma alteração no Roshambo String.linkify () no emailAddressPattern para reconhecer os endereços aaa.bbb. @ Ccc.ddd

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 *** here I've changed the expression ***
        var emailAddressPattern = /(([a-zA-Z0-9_\-\.]+)@[a-zA-Z_]+?(?:\.[a-zA-Z]{2,6}))+/gim;

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

O código acima falhará em muitos testes para casos extremos. Ao detectar URLs, é melhor contar com uma biblioteca especializada. Aqui está o porquê .
Dan Dascalescu

9

Eu procurei no google por algo mais novo e deparei com este:

$('p').each(function(){
   $(this).html( $(this).html().replace(/((http|https|ftp):\/\/[\w?=&.\/-;#~%-]+(?![\w\s?&.\/;#~%"=-]*>))/g, '<a href="$1">$1</a> ') );
});

demo: http://jsfiddle.net/kachibito/hEgvc/1/

Funciona muito bem para links normais.


O que é "Links normais" aqui? Veja a bifurcação da sua demonstração aqui: jsfiddle.net/hEgvc/27 As pessoas cobririam descobertas e tornariam isso fácil. O URI não é algo fácil de acordo com o RFC3986 e, se você gostaria de cobrir apenas "links normais", sugiro seguir este regexp pelo menos: ^ (([[::??] +):)?) (// ([ ^ /? #] *))? ([^? #] *) (\? ([^ #] *))? (# (. *))?
Ivan

2
Eu quis dizer qualquer coisa no formato http://example.com/folder/folder/folder/ou https://example.org/blahetc - apenas o seu formato de URL não louco que corresponderá a 95-99% dos casos de uso existentes. Estou usando isso para uma área administrativa interna, portanto não preciso de nada sofisticado para capturar casos extremos ou hashlinks.
degenerada


5

Essa solução funciona como muitas outras e, de fato, usa o mesmo regex que um deles, no entanto, em vez de retornar uma String HTML, isso retornará um fragmento de documento que contém o elemento A e quaisquer nós de texto aplicáveis.

 function make_link(string) {
    var words = string.split(' '),
        ret = document.createDocumentFragment();
    for (var i = 0, l = words.length; i < l; i++) {
        if (words[i].match(/[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi)) {
            var elm = document.createElement('a');
            elm.href = words[i];
            elm.textContent = words[i];
            if (ret.childNodes.length > 0) {
                ret.lastChild.textContent += ' ';
            }
            ret.appendChild(elm);
        } else {
            if (ret.lastChild && ret.lastChild.nodeType === 3) {
                ret.lastChild.textContent += ' ' + words[i];
            } else {
                ret.appendChild(document.createTextNode(' ' + words[i]));
            }
        }
    }
    return ret;
}

Existem algumas ressalvas, nomeadamente com o suporte do IE e do textContent mais antigo.

aqui está uma demonstração.


2
@DanDascalescu Em vez de uma votação geral baixa, talvez forneça seus casos extremos.
Rlemon 21/02

Eu preciso? Dê uma olhada no componente regexp para URLs . Mas se você insistir, corra contra o conjunto de testes de linkify de Ben Alman . Comecei a contribuir com testes falhos , por exemplo, para urlize , mas logo percebi que vale a pena fazer isso apenas para esforços sérios da biblioteca. Com todo o respeito, a pergunta acima é uma resposta do StackOverflow, não uma biblioteca de código aberto que tenta analisar os URLs corretamente.
Dan Dascalescu

2
então existem casos extremos. Maravilhoso. essas respostas ainda podem ser úteis para os outros, e a cobertura de sua votação parece exagerada. As outras respostas que você comentou e aparentemente downvoted Do contêm informações úteis (assim como a sua resposta). nem todos se opõem a esses casos e nem todos desejam usar uma biblioteca.
Rlemon 21/02

Exatamente. Aqueles que não entendem as limitações dos regexps são aqueles que alegremente examinam o primeiro regexp da resposta mais votada e a seguem. Essas são as pessoas que mais devem usar as bibliotecas.
Dan Dascalescu

1
Mas como é essa justificativa para rejeitar todas as respostas com regexp de soluções não preferidas?
Rlemon 21/02

4

Se você precisar mostrar um link mais curto (apenas domínio), mas com o mesmo URL longo, tente minha modificação da versão do código de Sam Hasler postada acima

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

3

Reg Ex: /(\b((https?|ftp|file):\/\/|(www))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]*)/ig

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

Abaixo estão algumas strings testadas:

  1. Encontre-me em www.google.com
  2. www
  3. Encontre-me em www. http://www.com
  4. Siga-me em: http://www.nishantwork.wordpress.com
  5. http://www.nishantwork.wordpress.com
  6. Siga-me em: http://www.nishantwork.wordpress.com
  7. https://stackoverflow.com/users/430803/nishant

Nota: Se você não quiser passar wwwcomo válido, use abaixo de reg ex: /(\b((https?|ftp|file):\/\/|(www))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig


O código acima falhará em muitos testes para casos extremos. Ao detectar URLs, é SEMPRE melhor confiar em uma biblioteca especializada. Aqui está o porquê .
Dan Dascalescu

3

Os avisos sobre a complexidade do URI devem ser observados, mas a resposta simples para sua pergunta é:
Para substituir todas as correspondências, você precisa adicionar o /gsinalizador ao final do RegEx:
/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gi


3
/**
 * Convert URLs in a string to anchor buttons
 * @param {!string} string
 * @returns {!string}
 */

function URLify(string){
  var urls = string.match(/(((ftp|https?):\/\/)[\-\w@:%_\+.~#?,&\/\/=]+)/g);
  if (urls) {
    urls.forEach(function (url) {
      string = string.replace(url, '<a target="_blank" href="' + url + '">' + url + "</a>");
    });
  }
  return string.replace("(", "<br/>(");
}

exemplo simples


2

Mantenha simples! Diga o que você não pode ter, em vez do que você pode ter :)

Como mencionado acima, os URLs podem ser bastante complexos, especialmente após o '?', E nem todos começam com um 'www'. por exemplomaps.bing.com/something?key=!"£$%^*()&lat=65&lon&lon=20

Portanto, em vez de ter uma regex complexa que não atenda a todos os casos extremos e será difícil de manter, que tal essa mais simples, que funciona bem para mim na prática.

Combine

http(s):// (anything but a space)+

www. (anything but a space)+

Onde "qualquer coisa" é [^'"<>\s] ... basicamente uma combinação gananciosa, levando você a encontrar um espaço, cotação, colchete angular ou fim de linha

Além disso:

Lembre-se de verificar se ele ainda não está no formato de URL, por exemplo, o texto contém href="..."ousrc="..."

Adicione ref = nofollow (se apropriado)

Essa solução não é tão "boa" quanto as bibliotecas mencionadas acima, mas é muito mais simples e funciona bem na prática.

if html.match( /(href)|(src)/i )) {
    return html; // text already has a hyper link in it
    }

html = html.replace( 
            /\b(https?:\/\/[^\s\(\)\'\"\<\>]+)/ig, 
            "<a ref='nofollow' href='$1'>$1</a>" 
            );

html = html.replace( 
            /\s(www\.[^\s\(\)\'\"\<\>]+)/ig, 
            "<a ref='nofollow' href='http://$1'>$1</a>" 
            );

html = html.replace( 
             /^(www\.[^\s\(\)\'\"\<\>]+)/ig, 
            "<a ref='nofollow' href='http://$1'>$1</a>" 
            );

return html;

2

A detecção correta de URL com domínios internacionais e suporte a caracteres astrais não é algo trivial. linkify-itA biblioteca cria regex a partir de várias condições e o tamanho final é de aproximadamente 6 kilobytes :). É mais preciso do que todas as bibliotecas, atualmente referenciado em resposta aceita.

Veja a demonstração do linkify-it para verificar ao vivo todos os casos extremos e testar os seus.

Se precisar vincular a fonte HTML, você deve analisá-la primeiro e iterar cada token de texto separadamente.



0

Eu tive que fazer o oposto e criar links html apenas na URL, mas modifiquei seu regex e ele funciona como um encanto, obrigado :)

var exp = /<a\s.*href=['")(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_ |!:,.;] * [- A-Z0-9 + & @ # \ /% = ~ _ |]) ['"]. *>. * <\ / A> / ig;

source = source.replace (exp, "$ 1");

Não vejo o objetivo do seu regex. Combina tudo, substituindo tudo por tudo. Com efeito, seu código não faz nada.
Chad Grant

8
Acho que devo esperar para comentar para permitir que as pessoas terminem a edição. desculpa.
Chad Grant #

0

A detecção de email na resposta do Travitron acima não funcionou para mim, então eu a estendi / substituí pela seguinte (código C #).

// Change e-mail addresses to mailto: links.
const RegexOptions o = RegexOptions.Multiline | RegexOptions.IgnoreCase;
const string pat3 = @"([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,6})";
const string rep3 = @"<a href=""mailto:$1@$2.$3"">$1@$2.$3</a>";
text = Regex.Replace(text, pat3, rep3, o);

Isso permite endereços de email como " firstname.secondname@one.two.three.co.uk ".


O código acima falhará em muitos testes para casos extremos. Ao detectar URLs, é SEMPRE melhor confiar em uma biblioteca especializada. Aqui está o porquê .
Dan Dascalescu

Obrigado, @DanDascalescu Normalmente, é sempre melhor generalizar demais.
Uwe Keim

0

Após a entrada de várias fontes, agora tenho uma solução que funciona bem. Tinha a ver com escrever seu próprio código de substituição.

Resposta .

Violino .

function replaceURLWithHTMLLinks(text) {
    var re = /(\(.*?)?\b((?:https?|ftp|file):\/\/[-a-z0-9+&@#\/%?=~_()|!:,.;]*[-a-z0-9+&@#\/%=~_()|])/ig;
    return text.replace(re, function(match, lParens, url) {
        var rParens = '';
        lParens = lParens || '';

        // Try to strip the same number of right parens from url
        // as there are left parens.  Here, lParenCounter must be
        // a RegExp object.  You cannot use a literal
        //     while (/\(/g.exec(lParens)) { ... }
        // because an object is needed to store the lastIndex state.
        var lParenCounter = /\(/g;
        while (lParenCounter.exec(lParens)) {
            var m;
            // We want m[1] to be greedy, unless a period precedes the
            // right parenthesis.  These tests cannot be simplified as
            //     /(.*)(\.?\).*)/.exec(url)
            // because if (.*) is greedy then \.? never gets a chance.
            if (m = /(.*)(\.\).*)/.exec(url) ||
                    /(.*)(\).*)/.exec(url)) {
                url = m[1];
                rParens = m[2] + rParens;
            }
        }
        return lParens + "<a href='" + url + "'>" + url + "</a>" + rParens;
    });
}

2
O código acima (e a maioria das expressões regulares em geral) falhará em muitos testes para casos extremos. Ao detectar URLs, é melhor contar com uma biblioteca especializada. Aqui está o porquê .
Dan Dascalescu

Dan, existe uma biblioteca assim? Embora, neste caso, ainda assim correspondamos ao regex acima, para que o código nunca possa gerar lixo quando algo como lixo (mesmo que outra biblioteca ateste o lixo como um URL / URI válido) seja usado como entrada.
Mike Mestnik


0

Aqui está a minha solução:

var content = "Visit https://wwww.google.com or watch this video: https://www.youtube.com/watch?v=0T4DQYgsazo and news at http://www.bbc.com";
content = replaceUrlsWithLinks(content, "http://");
content = replaceUrlsWithLinks(content, "https://");

function replaceUrlsWithLinks(content, protocol) {
    var startPos = 0;
    var s = 0;

    while (s < content.length) {
        startPos = content.indexOf(protocol, s);

        if (startPos < 0)
            return content;

        let endPos = content.indexOf(" ", startPos + 1);

        if (endPos < 0)
            endPos = content.length;

        let url = content.substr(startPos, endPos - startPos);

        if (url.endsWith(".") || url.endsWith("?") || url.endsWith(",")) {
            url = url.substr(0, url.length - 1);
            endPos--;
        }

        if (ROOTNS.utils.stringsHelper.validUrl(url)) {
            let link = "<a href='" + url + "'>" + url + "</a>";
            content = content.substr(0, startPos) + link + content.substr(endPos);
            s = startPos + link.length;
        } else {
            s = endPos + 1;
        }
    }

    return content;
}

function validUrl(url) {
    try {
        new URL(url);
        return true;
    } catch (e) {
        return false;
    }
}

0

Experimente a função abaixo:

function anchorify(text){
  var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
  var text1=text.replace(exp, "<a href='$1'>$1</a>");
  var exp2 =/(^|[^\/])(www\.[\S]+(\b|$))/gim;
  return text1.replace(exp2, '$1<a target="_blank" href="http://$2">$2</a>');
}

alert(anchorify("Hola amigo! https://www.sharda.ac.in/academics/"));


0

Experimente abaixo a solução

function replaceLinkClickableLink(url = '') {
let pattern = new RegExp('^(https?:\\/\\/)?'+
        '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|'+
        '((\\d{1,3}\\.){3}\\d{1,3}))'+
        '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+
        '(\\?[;&a-z\\d%_.~+=-]*)?'+
        '(\\#[-a-z\\d_]*)?$','i');

let isUrl = pattern.test(url);
if (isUrl) {
    return `<a href="${url}" target="_blank">${url}</a>`;
}
return url;
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.