在文本string中检测(淘气或漂亮的)URL或链接

我如何检测(使用正则expression式或启发式)网站链接在一个文本string,如评论?

目的是防止垃圾邮件。 HTML被剥离,所以我需要检测复制和粘贴的邀请。 由于大多数用户无法成功进入该页面,所以垃圾邮件发布者不应该经济地发布链接 。 我希望提出build议,参考或讨论最佳做法。

一些目标:

  • 像结构良好的URL( http://some-fqdn/some/valid/path.ext
  • url但没有http://前缀(即有效的FQDN +有效的HTTPpath)
  • 任何其他有趣的业务

当然,我正在阻止垃圾邮件,但同样的过程可以用来自动链接文本。

思路

这是我在想的一些事情。

  • 内容是本土语言散文,所以我可以触发,愉快的检测
  • 我是否应该首先www .example.com所有的空白,以捕捉“ www .example.com ”? 普通用户是否知道要自己删除空间,或者做任何浏览器“我是什么意思”并将其剥离?
  • 也许多次通过是一个更好的策略,扫描:
    • 格式良好的url
    • 所有非空白,然后是'。' 之后是任何有效的TLD
    • 还要别的吗?

相关问题

我已经阅读了这些内容,现在在这里logging下来,所以如果你愿意,你可以在这些问题中引用正则expression式。

  • 用HTML链接javascriptreplaceURL
  • 什么是最好的正则expression式来检查一个string是否是一个有效的URL
  • 获取URL的部分(正则expression式)

更新和总结

哇,我有一些非常好的启发式在这里列出! 对我来说,最好的巴克是一个综合以下内容:

  1. @Jon Bright的检测顶级域名(TLD)的技术(一个很好的防御阻塞点)
  2. 对于那些可疑的string,用@caparreplace点状字符
  3. 一个好看点的angular色是@Sharkey的下标· (即“ · ”)。 · 也是一个字的边界,所以很难随便复制和粘贴。

这应该使垃圾邮件发送者的CPM足够低以满足我的需求; “标志不当”的用户反馈应该抓住其他的东西。 列出的其他解决scheme也非常有用:

  • 去掉所有的虚线四边形(@ Sharkey对自己的答案的评论)
  • @ Sporkmonger对客户端Javascript的要求是在表单中插入一个必需的隐藏字段。
  • Ping URL服务器端来确定它是否是一个网站。 (也许我可以通过SpamAssassin或另一个贝叶斯filter按照@Nathan运行HTML。)
  • 看看Chrome的智能地址栏的来源,看看谷歌使用什么巧妙的技巧
  • 调用OWASP AntiSAMY或其他Web服务来检测垃圾邮件/恶意软件。

我正在集中我的回答,试图避免垃圾邮件。 这导致了两个假设:使用系统的人将因此积极地试图违反你的支票,你的目标只是检测URL的存在,而不是提取完整的URL。 如果你的目标是别的东西,这个解决scheme看起来会不一样

我认为你最好的select就是和TLD在一起。 有两个字母的ccTLD和(目前)比较小的其他列表。 这些需要用一个圆点作为前缀,并加上斜杠或一些字的边界。 正如其他人所指出的,这不会是完美的。 没有办法让“buyfunkypharmaceuticals。it”没有禁止合法的“我再次尝试,这是行不通的”或类似的。 所有这一切说,这将是我的build议:

 [^\b]\.([a-zA-Z]{2}|aero|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel)[\b/] 

事情会得到:

  • buyfunkypharmaceutical s.it
  • googl e.com
  • http:// stackoverflo ** w.com / ** questions / 700163 /

一旦人们开始混淆他们的URL,它就会中断,取而代之的是“。”。 与“点”。 但是,再次假设垃圾邮件发送者是你的目标,如果他们开始做这种事情,他们的点击率将会下降几个数量级。 那些足够了解垃圾网站的人,以及那些不知情的访问垃圾网站的人,我认为这是一个微乎其微的交叉口。 这个解决scheme应该让你检测所有复制和粘贴到地址栏的URL,同时将附带损害保持在最低限度。

检查这些文章:

  • URL的问题
  • 检测文本块中的URL

我不确定是否用正则expression式检测URL是解决这个问题的正确方法。 通常情况下,你会错过一些垃圾邮件发送者如果有足够的动机就能够利用的一些晦涩的边缘情况。

如果你的目标只是过滤垃圾评论,那么你可能要考虑贝叶斯过滤。 事实certificate,将电子邮件标记为垃圾邮件是非常准确的,但也可以为您做同样的事情,具体取决于您需要过滤的文本的数量。

我知道这不利于自动链接文本,但如果您search并replace所有完整句点与一个看起来像是一样的东西,如希伯来语点hiriq(U + 05B4)的Unicode字符?

以下段落是一个例子:

这可能工作ִ这段时间看起来有点奇怪,但它仍然是可读的ִ当然好处是任何人复制和粘贴wwwִgoogleִcom不会太远ִ:)

那么,显然低挂果实是以http://和www开头的东西。 试图过滤掉“www。g mail。com”这样的东西会导致一个有趣的哲学问题,就是你想要走多远。 你想下一步,并过滤出“www dot gee mail dot com”吗? 如何抽象描述一个URL,如“万维网的缩写,后面跟着一个点,后面跟着字母g,然后是单词后面跟着一个点,用TLD的商业缩写结束”。

在继续尝试devisealgorithm之前,先画出要尝试过滤的内容是非常重要的。 我认为这行应该是在“gmail.com”被认为是url的级别,但“gmail。com”不是。 否则,每次有人不能把一个句子中的第一个字母大写时,你可能会得到误报。

由于您主要在寻找复制并粘贴到浏览器地址栏的邀请,因此可能需要查看开源浏览器(例如Chrome或Mozilla)中使用的代码,以确定是否将文本input到“地址栏等同“是search查询或URL导航尝试。

Ping可能的URL

如果你不介意一点点的服务器端计算,那么这样的事情呢?

 urls = [] for possible_url in extracted_urls(comment): if pingable(possible_url): urls.append(url) #you could do this as a list comprehension, but OP may not know python 

这里:

  1. extracted_urls采取评论,并使用保守的正则expression式来拉出可能的候选人

  2. pingable实际上使用系统调用来确定Web上是否存在主机名。 你可以有一个简单的包装parsing的输出。

    [ramanujan:〜/ base] $ ping -c 1 http://www.google.com

    PING http://www.l.google.com(74.125.19.147):56个数据字节来自74.125.19.147的64字节:icmp_seq = 0 ttl = 246时间= 18.317 ms

    http://www.l.google.com ping统计数据— 1个数据包传输,1个数据包接收,0%丢包往返最小/平均/最大/ stddev = 18.317 / 18.317 / 18.317 / 0.000毫秒

    [ramanujan:〜/ base] $ ping -c 1 fooalksdflajkd.com

    ping:无法parsingfooalksdflajkd.com: 未知的主机

缺点是,如果主机给404,你不会检测到,但这是一个非常好的第一次切 – validation地址是一个网站的最终方法是尝试导航到它。 你也可以尝试wget'ing这个URL,但是这更重量级。

经过多次尝试编写这段精确的代码,我可以明确地说,你绝对不可能做到绝对可靠,你当然不能检测RFC允许的所有URIforms。 幸运的是,由于您拥有一组非常有限的url,因此您可以使用上述任何一种技术。

然而,我可以肯定地说,如果你真的想击败垃圾邮件发送者,那么最好的办法就是使用JavaScript。 发送一个执行一些计算的JavaScript块,然后在服务器端重复计算。 JavaScript应该将计算结果复制到隐藏字段中,以便在提交注释时提交计算结果。 在服务器端validation计算是否正确。 围绕这种技术的唯一方法是垃圾邮件发送者手动input注释或让他们开始为您运行JavaScript引擎。 我使用这种技术将我的网站上的垃圾邮件从100 + /天减less到每年一到两个。 现在唯一的垃圾邮件是由人类手动input的。 讨论垃圾邮件很奇怪。

当然,你意识到如果垃圾邮件发送者决定使用tinuyrl或这样的服务来缩短他们的URL,你的问题就会变得更糟。 在这种情况下,您可能需要编写一些代码来查找实际的URL,使用像TinyURL解码器这样的服务

考虑纳入OWASP AntiSAMY API …

我喜欢capar的答案迄今为止最好,但处理unicode字体可能会有点充满,与旧的浏览器往往显示一个有趣的事情或一个小盒子…和U + 05B4的位置有点奇怪。 ..对我来说,它出现在这里的pipe道|ִ| 即使是在他们之间。

有一个方便&middot; (·)虽然,打破了同样的方式剪贴。 它的垂直alignment可以通过<sub>来纠正,例如:

stackoverflow · com

歪曲,但在FF3有效,它不能被剪切和粘贴为URL。 <sub>实际上是相当不错的,因为它显而易见地显示为什么URL不能被粘贴。

不在可疑URL中的点可以单独留下,例如你可以这样做

 s/\b\.\b/<sub>&middot;<\/sub>/g 

另一种select是在怀疑点旁边插入某种零宽度的实体,但是像&zwj; 和&zwnj; 和&amp; mpsp; 似乎没有在FF3工作。

这里已经有一些很好的答案,所以我不会发表更多。 我会给一些陷阱。 首先,确保testing已知的协议,其他任何东西都可能是顽皮的。 作为一个爱好telnet连接的人,你可能想要在你的search中包含多个http,但是可能想要阻止目标:或者其他的url。 其次,很多人会用< http://theroughnecks.net >或者parens(url)的方式在angular括号(gt / lt)中划分它们的链接,没有比单击一个链接更糟糕的了, >或)与其余的url去allong。

PS抱歉的自我参考插头;)