2014-05-08 38 views
3

这应该很简单,但它让我难以置信。有很多好的和坏的正则表达式方法来匹配一个URL,无论是否使用协议,使用或不使用www。我遇到的问题是这样的(在JavaScript中):如果我使用正则表达式来匹配文本字符串中的URL,并将其设置为只匹配'domain.com',它还会捕获电子邮件地址的域'@'之后的部分),我不想要。一个负面的背后隐藏解决了它 - 但显然不在JS中。正则表达式匹配domain.com,但不支持@ domain.com

这是迄今为止我最近的成功:

/^(www\.)?([^@])([a-z]*\.)(com|net|edu|org)(\.au)?(\/\S*)?$/g 

但如果比赛是不是在字符串的开头失败。而且我相信我正在以错误的方式解决问题。那里有一个简单的答案吗?

编辑:修正则表达式来几个下面的评论作出回应(孜孜以求的“www”,而不是让子域:

\b(www\.)?([^@])(\w*\.)(\w{2,3})(\.\w{2,3})?(\/\S*)?$ 

正如但是评论中提到,这仍然域名之后匹配一个@。

感谢

+0

This [question](http://stackoverflow.com/questions/641407/javascript-negative-lookbehind-equivalent)* may * help。 – merlin2011

+5

备注:您是否知道有大量新TLD可用或即将可用? – Marty

+0

也许你可以通过http://regexr.com/ – HJ05

回答

0

经过大量的搞砸之后,这个结束了工作(用一个确定的帽子ti p来@ ZMO的最后评论):

var rx = /\b(www\.)?(\w*@)?([a-zA-Z\-]*\.)(com|org|net|edu|COM|ORG|NET|EDU)(\.au)?(\/\S*)?/g; 
var link = txt.match(rx); 
    if(link !== null) { 
    for(var i = 0; i < link.length; i++) { 
     if (link[i].indexOf('@') == -1) { 
     //create link 
     } else { 
     //create mailto; 
     } 
     } 
     } 

我知道的局限性,对于子域,顶级域名等(其中@ ZMO上面已经解决了 - 如果你需要捕获所有的网址,我建议你修改该代码),但这不是我的情况中的主要问题。我的答案中的代码允许匹配不带“www。”的文本字符串中的网址,也不会捕获电子邮件地址的域。

1

如果比赛不在字符串的开头失败

那是因为^在比赛的开始:

/(www\.)?([^@])([a-z]*\.)(com|net|edu|org)(\.au)?(\/\S*)?$/g

js> "www.foobar.com".match(/(www\.)?([^@])([a-z]*\.)(com|net|edu|org)(\.au)?(\/\S*)?$/g) 
["www.foobar.com"] 
js> "aoeuaoeu foobar.com".match(/(www\.)?([^@])([a-z]*\.)(com|net|edu|org)(\.au)?(\/\S*)?$/g) 
[" foobar.com"] 
js> "[email protected] foobar.com".match(/(www\.)?([^@])([a-z]*\.)(com|net|edu|org)(\.au)?(\/\S*)?$/g) 
[" foobar.com"] 
js> "[email protected] [email protected]".match(/(www\.)?([^@])([a-z]*\.)(com|net|edu|org)(\.au)?(\/\S*)?$/g) 
["foobar.com"] 

虽然它仍然匹配域之前的空间。这是对域的错误假设...

  • xyz.example.org是与您的正则表达式不匹配的有效域;
  • www.3x4mpl3.org是与您的正则表达式不匹配的有效域;
  • example.co.uk是与您的正则表达式不匹配的有效域;
  • ουτοπία.δπθ.gr是与您的正则表达式不匹配的有效域。

什么定义了合法域名?它只是由点分隔的一系列utf-8字符。它不能有两个点,并且规范名称是\w\.\w\w(因为我不认为一个字母tld存在)。

虽然,我会做的方式是简单地匹配一切看起来像域,采取一切,是文本用点分隔使用单词边界(\b):

/\b(\w+\.)+\w+\b/g

js> "aoe toto.example.org uaoeu foo.bar aoeuaoeu".match(/\b(\w+\.)+\w+\b/g) 
["toto.example.org", "foo.bar"] 
js> "aoe [email protected] toto.example.org uaoeu foo.bar aoeuaoeu".match(/\b(\w+\.)+\w+\b/g) 
["example.org", "toto.example.org", "foo.bar"] 
js> "aoe [email protected] toto.example.org uaoeu foo.bar aoeuaoeu f00bar.com".match(/\b(\w+\.)+\w+\b/g) 
["example.org", "toto.example.org", "foo.bar", "f00bar.com"] 

然后进行第二轮检查域是否确实存在或不在发现的域列表中。缺点是JavaScript中的正则表达式无法检查unicode字符,并且\b\w将不接受ουτοπία.δπθ.gr作为有效的域名。

在ES6,还有的/u modifier,这应与最新的浏览器中工作(但没有,我迄今已检测):

"ουτοπία.δπθ.gr aoe [email protected] toto.example.org uaoeu foo.bar aoeuaoeu".match(/\b(\w+\.)+\w+\b/gu) 

编辑:

负回顾后解决它 - 但显然不在JS中。

是的,它会:跳过所有的电子邮件地址,这里的落后执行正则表达式的工作看:

/(?![^@])?\b(\w+\.)+\w+\b/g

js> "aoe [email protected] toto.example.org uaoeu foo.bar aoeuaoeu f00bar.com".match(/(?<![^@])?\b(\w+\.)+\w+\b/g) 
["toto.example.org", "foo.bar", "f00bar.com"] 

尽管它同样为Unicode ...它”即将在那里在JS很快...

唯一的方法就是,实际上保留@在匹配的正则表达式,并放弃任何匹配包含一个@:

js> "toto.net aoe [email protected] toto.example.org uaoeu foo.bar aoeuaoeu f00bar.com".match(/@?\b\w+\.+\w+\b/g).map(function (x) { if (!x.match(/@/)) return x }) 
["toto.net", (void 0), "toto.example", "foo.bar", "f00bar.com"] 

或使用来自ES6/JS1.7新的列表理解,这应该是没有在现代浏览器...

[x for x of "toto.net aoe [email protected] toto.example.org uaoeu foo.bar aoeuaoeu f00bar.com".match(/@?\b\w+\.+\w+\b/g) if (!x.match(/@/))]; 

一个最后更新:

/@?\b(\w*[^\W\d]+\w*\.+)+[^\W\d_]{2,}\b/g

> "x.y tot.toc.toc $11.00 11.com 11foo.com toto.11 toto.net aoe [email protected] toto.example.org uaoeu foo.bar aoeuaoeu f00bar.com".match(/@?\b(\w*[^\W\d]+\w*\.+)+[^\W\d_]{2,}\b/g).filter(function (x) { if (!x.match(/@/)) return x }) 
[ 'tot.toc.toc', 
    '11foo.com', 
    'toto.net', 
    'toto.example.org', 
    'foo.bar', 
    'f00bar.com' ] 
+0

在regex101.com上验证失败,但似乎通过了Firebug。无论如何,我都会更新它,以防止它捕获诸如“$ 1”之类的内容。(\ w \ 2,3})(\/\)(\ w {2,3}) S *)\ b/g标准;'。如果我将它放在我的电子邮件匹配代码之前,它仍然匹配域,然后电子邮件匹配失败。如果我在电子邮件匹配后匹配URL,它可以工作,但它似乎做了很多工作,因为它匹配文本和mailto href。至少一切正常。所以,我不确定这是否是答案。无论如何,谢谢。 – sideroxylon

+1

好吧,您应该匹配电子邮件和fqdn,然后将电子邮件过滤到您的电子邮件转换代码,并将域转换为域转换代码。这会让事情变得更简单。尽管www开始一个域名是错误的。但是一个域不能只有数字,它至少需要一个字母。无论如何,只有一种标准的方式来测试域名:它实际上是针对DNS注册表进行检查。 – zmo

+0

添加了一个正则表达式,它仅基于数字tld或仅数字域或一个字符tld删除无效域。 – zmo