如何匹配文本中的URI?

时间:2020-03-05 18:58:40  来源:igfitidea点击:

如何在文本块中发现URI?

想法是将这些文本运行转换为链接。如果仅考虑http(s)和ftp(s)方案,这将非常简单。但是,我猜测一般问题(考虑tel,mailto和其他URI方案)要复杂得多(如果可能的话)。

我希望在Cif中提供解决方案。谢谢你。

解决方案

回答

对于许多协议,我们可以只搜索"://"而不加引号。虽然不确定其他人。

回答

某些内容是否为URI取决于上下文。通常,它们唯一的共同点是它们以" scheme_name:"开头。方案名称可以是任何名称(以合法字符为准)。但是其他字符串也包含冒号,而不是URI。

因此,我们需要确定感兴趣的方案。通常,对于我们关心的每种方案,我们都可以搜索" scheme_name:",然后是字符,直到空格为止。不幸的是,URI可以包含空格,因此,如果将它们嵌入文本中,则可能会造成歧义。我们无法采取任何措施来解决编写文本的人必须解决的歧义。 URI可以选择包含在<>中。不过,大多数人都不会这样做,因此认识到这种格式只会偶尔有所帮助。

URI的Wikipedia文章列出了相关的RFC。

[编辑添加:使用正则表达式完全验证URI是一场噩梦,即使我们以某种方式找到或者创建了正确的URI,也将非常庞大,并且难以注释和维护。幸运的是,如果我们正在做的是突出显示链接,那么我们可能不需要关心奇数假阳性,因此我们无需进行验证。只需查找" http://"," mailto:\ S * @"等)

回答

这是带有正则表达式的代码片段,可满足各种需求:

http://snipplr.com/view/6889/regular-expressions-for-uri-validationparsing/

回答

如果我们还希望匹配" something.tld",这并不容易,因为普通文本将具有该模式的许多实例,但是如果我们仅希望匹配以方案开头的URI,则可以尝试使用此正则表达式(对不起,我不知道如何将其插入C#)

(http|https|ftp|mailto|tel):\S+[/a-zA-Z0-9]

我们可以在此处添加更多方案,并且要考虑到最后一个字符不是无效的字符(例如,如通常的字符串" http://www.example.com"那样,它会与方案匹配直到下一个空格字符)。 )

回答

下面的perl regexp应该可以解决问题。 chave perl正则表达式吗?

/\w+:\/\/[\w][\w\.\/]*/

回答

正则表达式可能证明是一个很好的起点,尽管众所周知,URI和URL很难与单个模式匹配。

为了说明这一点,最简单的模式看起来相当复杂(用Perl 5表示法):

\ w +:\ / {2} [\ d \ w-] +(\。[\ d \ w-] +)*(?:(?:\ / [^ \ s /] *))*

这将匹配
http:// example.com / foo / bar-baz


ftp://192.168.0.1/foo/file.txt

但至少会造成以下问题:

  • mailto:[email protected](不匹配-没有//,但存在@)
  • ftp://192.168.0.1.2(匹配,但数量太多,因此不是有效的URI)
  • ftp://1000.120.0.1(匹配,但是IP地址需要0到255之间的数字,因此它不是有效的URI)
  • nonexistantscheme:// obvious.false.positive
  • " http://www.google.com/search?q=uri+regular+expression"(匹配,但是查询不是我认为这是80:20规则的一种情况。然后我会建议我们找到一个不错的正则表达式,如果我们自己不能自己写的话。

如果我们正在查看从相当可控的来源(例如机器生成的)中提取的文字,那么这将是最好的选择。

如果我们绝对肯定要捕获遇到的每个URI,并且正在查看文本,那么我想我会寻找其中带有冒号的任何单词,例如\ s(\ w:\ S +)\ s`。一旦找到合适的URI候选者,然后将其传递给所使用的任何库的URI类中的真实URI解析器。

如果我们对为什么很难编写URI模式感兴趣,我想可能是URI的定义是使用Type-2语法完成的,而正则表达式只能解析Type-3语法中的语言。

回答

Ubiquity的URL工具执行以下操作:

findURLs: function(text) {
    var urls = [];
    var matches = text.match(/(\S+\.{1}[^\s\,\.\!]+)/g);
    if (matches) {
        for each (var match in matches) {
            urls.push(match);
        }
    }
    return urls;
},