如何将纯文本URL替换为链接?

490

我正在使用以下函数来匹配给定文本中的URL并将它们替换为HTML链接。正则表达式非常有效,但目前我只替换了第一个匹配项。

我应该如何替换所有的URL?我猜我应该使用exec命令,但我真的不知道如何做。

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>"); 
}
25个回答

1
这是我的解决方案:
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;
    }
}

1

经过多方提供的意见,我现在有了一个很好的解决方案。这涉及编写自己的替代代码。

答案

Fiddle

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
上面的代码(以及大多数正则表达式)在很多边缘情况下会失败很多测试。在检测 URL 时,最好依赖于专门的库。这就是为什么 - Dan Dascalescu
丹,有这样的库吗?尽管在这种情况下,我们仍将匹配上面的正则表达式,以便当输入类似垃圾的东西(即使另一个库将垃圾认证为有效的URL / URI)时,代码永远不会输出垃圾。 - Mike Mestnik

1

我需要做相反的事情,将HTML链接转换为纯URL,但我修改了你的正则表达式,现在它像魔法一样工作,谢谢 :)

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

我不明白你的正则表达式的意义。它匹配所有内容并用一切替换一切。实际上,你的代码什么也没做。 - Chad Grant
8
我想我应该等待评论,以便让人们完成编辑。抱歉。 - Chad Grant

0

0

对我有用:

var urlRegex =/(\b((https?|ftp|file):\/\/)?((([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_]*)?)/ig;

return text.replace(urlRegex, function(url) {
    var newUrl = url.indexOf("http") === -1 ? "http://" + url : url;
    return '<a href="' + newUrl + '">' + url + '</a>';
});

如果 URL 中含有 = 符号,则该代码不起作用。 - xinqiu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接