这应该很简单,但它不是我的意思。无论有无协议,有或没有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*)?$
正如评论中所提到的,这仍然与@之后的域匹配。
由于
答案 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,而不会捕获电子邮件地址的域。