如何用链接替换普通 URL?

IT技术 javascript regex
2021-01-13 22:45:18

我正在使用下面的函数来匹配给定文本中的 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>"); 
}
6个回答

首先,滚动您自己的正则表达式来解析 URL 是一个糟糕的主意根据RFC您必须想象这是一个足够普遍的问题,有人已经为它编写、调试和测试了一个库URI 很复杂- 查看Node.js 中 URL 解析代码URI 方案的 Wikipedia 页面

在解析 URL 时有很多边缘情况:国际域名、实际的 ( .museum) 与不存在的 ( .etc) TLD、奇怪的标点符号(包括括号)、URL 末尾的标点符号、IPV6 主机名等。

我已经看了一吨图书馆,并有几个值得使用,尽管一些缺点:

我已迅速取消此任务资格的图书馆:

如果您坚持使用正则表达式,最全面的是来自 ComponentURL regexp,尽管它会通过查看错误地检测到一些不存在的两字母 TLD。

奇怪的是没有人提到 John Gruber 在维护URL regex 模式方面所做的努力这不是问题的唯一/理想解决方案,但无论如何都值得研究,如果您正在推出自己的解决方案。只是想添加这个作为参考。
2021-03-26 22:45:18
遗憾的URL regexp from Component是没有评论,对它正在做什么的一些解释会有所帮助。Autolinker.js评论很好,有测试。尽管没有测试,但urlize.jsVebjorn Ljosa 的回答中链接到看起来也很有特色且维护良好。
2021-03-30 22:45:18
Autolinker.js 加 1,易于实现,如果您正在寻找快速解决方案。谢谢
2021-03-31 22:45:18
Regex101.com 会自动“解释”正则表达式,但祝你好运:) 我也很快发现了一个 TLD 无效的失败案例(相同的链接)。
2021-04-04 22:45:18
@DanDascalescu 看看这个markdown-it.github.io/linkify-it该库完全专注于一项任务 - 检测文本中的链接模式。但我希望,它做得很好。例如,它具有正确的 unicode 支持,包括星形字符。它支持国际顶级域名。
2021-04-07 22:45:18

用链接替换 ​​URL(一般问题的答案)

问题中的正则表达式遗漏了很多边缘情况。检测 URL 时,最好使用专门的库来处理国际域名、新 TLD(如.museum、括号和 URL 内部和末尾的其他标点符号以及许多其他边缘情况)。有关其他一些问题的解释,请参阅 Jeff Atwood 的博客文章URL问题。

URL 匹配库最佳摘要Dan Dascalescu 的回答中+100
(截至 2014 年 2 月)


“使一个正则表达式替换多个匹配项”(具体问题的答案)

在正则表达式末尾添加“g”以启用全局匹配:

/ig;

但这只能解决正则表达式仅替换第一个匹配项的问题。不要使用该代码。

我对 Travis 的代码做了一些小的修改(只是为了避免任何不必要的重新声明——但它非常适合我的需要,干得好!):

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;
}
我遇到了一些问题;首先只是 http:// 或 http:// www (没有空格www甚至 SO 显然解析这个错误)将创建一个链接。以及与 http://www 的链接。领域 。com(不带空格)将创建一个空链接,然后在 href 字段中创建一个附加锚点结束标记的链接。
2021-03-17 22:45:18
我试图编辑原始帖子以解决 mailto 问题,但我必须添加至少 6 个字符才能进行编辑。但是,如果您更改此行:replacePattern3 = /(\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,6})/gim;这样replacePattern3 = /(\w+@[a-zA-Z_]+?(\.[a-zA-Z]{2,6})+)/gim;可以解决 mailto 问题:)
2021-03-19 22:45:18
如何编辑此代码以不损害嵌入对象和 iframe ..(youtube 嵌入对象和 iframe)
2021-03-20 22:45:18
没有http://或 的URL 怎么样www这对那些类型的 URL 有效吗?
2021-03-22 22:45:18
代码中存在与此处的电子邮件地址匹配的错误。[a-zA-Z]{2,6}应该阅读一些类似的内容(?:[a-zA-Z]{2,6})+以匹配更复杂的域名,即 email@example.co.uk。
2021-03-25 22:45:18

Linkify()上面Travis 的代码做了一些优化我还修复了一个错误,即无法匹配子域类型格式的电子邮件地址(即 example@domain.co.uk)。

此外,我将实现更改为String类的原型,以便可以像这样匹配项目:

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

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

无论如何,这是脚本:

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>');
    };
}
它不适+用于电子邮件用户名,例如foo+bar@domain.com. 我用电子邮件模式修复了它/[\w.+]+@[a-zA-Z_-]+?(?:\.[a-zA-Z]{2,6})+/gim(注意+第一个括号中的),但我不知道这是否会破坏其他东西。
2021-03-15 22:45:18
似乎它不适用于这样的电子邮件地址:info@some-thing.com some.thing@example.com 等。
2021-03-17 22:45:18
@MarcoGagliardi 好收获。固定的。
2021-03-27 22:45:18
我认为最好的,因为 Prototype 函数让事情变得更清晰:)
2021-03-29 22:45:18
这不适用于字符串“git clone aaaa@bitbucket.org/ooo/bbb-cc-dd.git ”。它将字符串分成块并创建了多个锚点,例如“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> ”
2021-04-06 22:45:18

谢谢,这很有帮助。我还想要一些可以链接看起来像 URL 的东西——作为基本要求,它会链接类似于 www.yahoo.com 的东西,即使 http:// 协议前缀不存在。所以基本上,如果“www”。存在,它将链接它并假设它是 http://。我还希望电子邮件变成 mailto: 链接。示例:www.yahoo.com 将转换为 www.yahoo.com

这是我最终得到的代码(来自这个页面的代码和我在网上找到的其他东西的组合,以及我自己做的其他东西):

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
}

在第二次替换中,(^|[^/]) 部分仅替换 www.whatever.com,如果它尚未以 // 为前缀,则避免在第一次替换中已链接 URL 时出现双重链接。此外,www.whatever.com 可能位于字符串的开头,这是正则表达式该部分中的第一个“或”条件。

这可以集成为一个 jQuery 插件,如上面的 Jesse P 所示——但我特别想要一个不作用于现有 DOM 元素的常规函数​​,因为我正在获取我拥有的文本,然后将其添加到 DOM,并且我希望在添加文本之前“链接”文本,因此我通过此函数传递文本。效果很好。

上面的代码将无法通过边缘情况的大量测试。检测 URL 时,最好依靠专门的库。这就是为什么
2021-03-09 22:45:18
我只是在一个字符串上运行它,其中一些网络链接已经有一个 href 链接。在这种情况下,它无法破坏现有的工作链接。
2021-03-09 22:45:18
第二个模式有问题,它本身就匹配了简单的“www.domain.com”。当 url 中包含某种引用时,就会出现问题,例如:&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 - 在这种情况下,链接会再次自动链接。快速修复是在包含“/”的否定列表之后添加字符“f”。所以表达式为:replacePattern2 = /(^|[^\/f])(www\.[\S]+(\b|$))/gim
2021-03-14 22:45:18