这应该很简单,但这使我难以理解。无论有没有协议(protocol),有没有www,都有很多匹配正则表达式的好坏方法。我的问题是(在javascript中):如果我使用正则表达式来匹配文本字符串中的URL,并将其设置为仅与“domain.com”匹配,它还会捕获电子邮件地址的域( “@”后面的部分),我不希望这样。负向查找可以解决问题-但显然在JS中无法解决。

到目前为止,这是我最近的成功:

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

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

编辑:修改后的正则表达式以回应以下一些评论(坚持以“www”开头,而不是允许子域:
\b(www\.)?([^@])(\w*\.)(\w{2,3})(\.\w{2,3})?(\/\S*)?$

但是,如评论中所述,这仍然与@之后的域匹配。

谢谢

最佳答案



这是因为比赛开始时的^:
/(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中的正则表达式无法检查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)
    

    编辑:



    是的,它将:为了跳过所有电子邮件地址,下面是正则表达式实现的工作原理:
    /(?![^@])?\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' ]
    

    09-26 22:00
    查看更多