正则表达式匹配domain.com但不匹配@ domain.com

时间:2014-05-08 22:59:52

标签: javascript regex negative-lookbehind

这应该很简单,但它不是我的意思。无论有无协议,有或没有www,有许多好的和坏的正则表达式方法来匹配URL。我遇到的问题是(在javascript中):如果我使用正则表达式匹配文本字符串中的URL,并将其设置为只匹配' domain.com',它还会捕获域的域名电子邮件地址(' @'之后的部分),我不想要。消极的外观解决了它 - 但显然不是在JS中。

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

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

但如果匹配不在字符串的开头,则会失败。而且我确定我以错误的方式解决它。那里有简单的答案吗?

编辑:修改正则表达式以回应下面的一些评论(坚持使用'而不是允许子域名:

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

正如评论中所提到的,这仍然与@之后的域匹配。

由于

2 个答案:

答案 0 :(得分: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> "toto@aoeuaoeu foobar.com".match(/(www\.)?([^@])([a-z]*\.)(com|net|edu|org)(\.au)?(\/\S*)?$/g)
[" foobar.com"]
js> "toto@aoeuaoeu toto@foobar.com".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 toto@example.org toto.example.org  uaoeu foo.bar aoeuaoeu".match(/\b(\w+\.)+\w+\b/g)
["example.org", "toto.example.org", "foo.bar"]
js> "aoe toto@example.org 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中的regexp无法检查unicode字符,\b\w将不接受ουτοπία.δπθ.gr作为有效域名。

在ES6中,有/u modifier,它应该适用于最新的浏览器(但到目前为止我没有测试过):

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

编辑:

  

负面的外观解决了它 - 但显然不是在JS中。

是的,它会:跳过所有电子邮件地址,这是正则表达式实现背后的工作:

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

js> "aoe toto@example.org 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 toto@example.org 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 toto@example.org 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 toto@example.org 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' ]

答案 1 :(得分:0)

经过大量的捣乱后,最终工作(对@ 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。”的URL,而不会捕获电子邮件地址的域。