我正在尝试提取网址权限(没有协议和www。如果存在)以及它之后的所有内容(如果存在)。到目前为止我的正则表达式:
/^(?:http|https)?(?::\/\/)?(?:www\.)?(.*?)(\/.*)/;
这适用于包含所有内容的网址,例如:
http://www.site.com/part1/part2?key=value#blub
但是如果我将路径捕获组标记为可选:
/^(?:http|https)?(?::\/\/)?(?:www\.)?(.*?)(\/.*)?/
它不再匹配了。为什么呢?
现在,如果我让第一个变体匹配:
http://site.com
它将:
提取为第一个值(权限),将//site.com
提取为第二个(路径)。
我没想到这会起作用,因为它没有路径,路径也没有标记为可选。但仍然对这个结果感到好奇,因为我只有这两个捕捉组 - (.*?)(\/.*)
有人可以解释我的错误。请不要链接到完整的url解析解决方案,我知道有很多这些,但我想了解我的正则表达式有什么问题(以及我如何解决)。
感谢。
答案 0 :(得分:3)
user1436026在我即将点击提交按钮之前发布了JUST,但是这里是:
您的域(权限)模式被标记为“ungreedy”,其匹配尽可能少。在你的情况下,它实际上满足了模式,根本没有匹配任何东西 - 这几乎与它一样少。你想要的是让域尽可能匹配,直到你肯定它匹配的东西不再是域(我改变了正则表达式以匹配除了/之外的任何东西,并且尽可能多地找到它。)< / p>
/^(?:http|https)?(?::\/\/)?(?:www\.)?([^\/]+)(\/.*)?/
我知道你特别声明你不希望任何链接到JS中的任何URL解析解决方案,但你知道JS已经内置了吗? :)
var link = document.createElement('a');
link.href="http://www.site.com/part1/part2?key=value#blub";
auth=link.hostname; //www.site.com
path=link.pathname; // /part1/part2
答案 1 :(得分:2)
在正则表达式/^(?:http|https)?(?::\/\/)?(?:www\.)?(.*?)(\/.*)?/
结束时,(.*?)
(因为它有?
修饰符)正在尝试匹配为 little 为了满足正则表达式。因为你已经使你的正则表达式可选的最后一部分,(.*?)
不必匹配任何东西,以满足正则表达式的其余部分,因为允许(\/.*)?
没事。然而,当您将正则表达式的最后一部分强制,(\/.*)
时,(.*?)
被强制匹配,以使(\/.*)
匹配。< / p>
答案 2 :(得分:1)
互联网工程任务组(IETF)征求意见稿(RFC)文件号3986,标题为:“统一资源标识符(URI):通用语法”(RFC3986),是权威标准,描述了构成有效通用统一资源标识符(URI)的所有组件的精确语法。 Appendix B提供了您需要的正则表达式:
<强> ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
强>
使用此正则表达式,URI部分存储如下:
scheme = $2
authority = $4
path = $5
query = $7
fragment = $9
为了记录上面的正则表达式,我冒昧地用自由间距模式用注释和缩进重写它,并在这里以经过测试的PHP脚本的形式呈现它,它解析了所有主要部分给定URI字符串:
<?php // test.php Rev:20130830_0800
$re_rfc3986_parse_generic_uri = '%
# Parse generic URI according to RFC3986 Appendix B.
^ # Anchor to start of string.
(?: # Group for optional scheme.
([^:/?#]+) # $1: Uri SCHEME.
: # Scheme ends with ":".
)? # Scheme is optional.
(?: # Group for optional authority.
// # Authority starts with "//"
([^/?#]*) # $2: Uri AUTHORITY.
)? # Authority is optional.
([^?#]*) # $3: Uri PATH (required).
(?: # Group for optional query.
\? # Query starts with "?".
([^#]*) # $4: Uri QUERY.
)? # Query is optional.
(?: # Group for optional fragment.
\# # Fragment starts with "#".
(.*) # $5: Uri FRAGMENT.
)? # Fragment is optional.
$ # Anchor to end of string.
%x';
$text = "http://www.site.com/part1/part2?key=value#blub";
if (preg_match($re_rfc3986_parse_generic_uri, $text, $matches)) {
print_r($matches);
} else {
echo("String is not a valid URI");
}
?>
对原始正则表达式进行了两项功能更改:1。)将不必要的捕获组转换为非捕获,以及2.)在表达式结尾添加$
字符串锚点结束。请注意,可以使用命名捕获组而不是使用编号的捕获组来创建更具可读性的版本,但不能直接将其转移到JavaScript语法。
PHP脚本输出:
Array
(
[0] => http://www.site.com/part1/part2?key=value#blub
[1] => http
[2] => www.site.com
[3] => /part1/part2
[4] => key=value
[5] => blub
)
这是一个经过测试的JavaScript函数,它将有效的URI分解为各种组件:
// Parse a valid URI into its various parts per RFC3986.
function parseValidURI(text) {
var uri_parts;
var re_rfc3986_parse_generic_uri =
/^(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?$/;
// Use String.replace() with callback function to parse the URI.
text.replace(re_rfc3986_parse_generic_uri,
function(m0,m1,m2,m3,m4,m5) {
uri_parts = {
scheme : m1,
authority : m2,
path : m3,
query : m4,
fragment : m5
};
return; // return value is not used.
});
return uri_parts;
}
请注意,如果URI字符串中不存在,则返回的对象的非路径属性可能为undefined
。此外,如果URI字符串与此正则表达式不匹配(即它显然无效),则返回的值为undefined
。
对于那些对验证 URI并进一步分解它感兴趣的人,我写了一篇文章,其中包含RFC3986附录A中定义的所有部分,并将它们转换为正则表达式语法。参见:
快乐的复兴!