用于提取 URL 组件的正则表达式
regexp to extract an URL components
我正在尝试编写正则表达式来提取 URL 组件。语法可以在这里找到:RFC 3986.
有些组件是可选的。到目前为止我有:
(.+)://((.*)@)?(.+?)(:(\d*))?/((.*)\?)?((.*)#)?(.*)
分解为:
(.+)://
匹配后跟 ://
的方案。不可选。
((.*)@)?
匹配权限的用户信息部分。可选。
(.+?)
匹配主机。不是可选的。 这里有一个问题,这个组 也将匹配 可选端口。
(:(\d*))?
应该匹配端口。
/
这个和后面的所有内容都应该是可选的。
((.*)\?)?
匹配路径部分。可选。
((.*)#)?
匹配查询部分。可选。
(.*)
匹配片段部分。可选。
我如何改进此正则表达式以使其在 RFC3986 中有效?
有趣的事实:这个正则表达式匹配自身。
示例URL(取自RFC):foo://example.com:8042/over/there?name=ferret#nose
编辑:我忘了转义d
。现在剩下要做的就是使 host 之后的所有内容成为可选的,包括领先的 /
.
如果您只转义斜线,最好也转义冒号,您的正则表达式就可以正常工作。结果是(.+)\:\/\/(.*@)?(.+?)(:(\d*))?\/((.*)\?)?((.*)#)?(.*)
。这是一个简单的脚本,展示了如何使用它来过滤掉无效的 URI:
更新
根据评论,我做了以下修改:
- 我已经添加了
(\:((\d*)\/))?(\/)*
。解释:
\:((\d*)
匹配一个冒号,然后是任何数字串。
- 之后的
\/
匹配一个斜杠,该斜杠应该在这串数字之后。这是因为端口不能包含任何其他字符,只能包含数字。所以在uri的port-portion中是找不到的。
- 最后,整个 port-matching 表达式是可选的,因此
?
.
- 最后一部分表示 existing/non-existing 端口后可以有很多斜杠或没有斜杠
最终正则表达式:
(.+)\:\/\/(.*\@)?(.+?)(\:((\d*)\/))?(\/)*((.*)\?)?((.*)\#)?(.*)
const myRegEx = new RegExp("(.+)\:\/\/(.*\@)?(.+?)(\:((\d*)\/))?(\/)*((.*)\?)?((.*)\#)?(.*)", "g");
const allUris = [
/*Valid*/ "https://me@data.www.example.com:5050/page?query=value#element",
/*Valid*/ "foo://example.com:8042/over/there?name=ferret#nose",
/*Valid*/ "foo://example.com",
/*Not valid*/ "www.example.com"];
const allowedUris = allUris.map(uri => {
// Use the regexp to match it, then return the match
const match = uri.match(myRegEx);
return match;
});
console.log("Here are the valid URIs:");
console.log(allowedUris.join("\n\n")); // Should only print the first two URIs from the array.
我找到了一种更好的方法来处理这个问题,同时也不会破坏捕获组。
(\w[\w\d\+\.-]*)://(.+@)?([^:/\?#]+)(:\d+)?(/[^\?#]*)?(\?[^#]+)?(#.*)?
分解:
(\w[\w\d\+\.-]*)://
根据 RFC-3986 匹配有效方案。
(.+@)?
匹配用户信息;即 @
之前的所有内容,可选。
([^:/\?#]+)
匹配主机;即,遇到 :
或 /
或 ?
或 #
之前的所有内容。
(:\d+)?
匹配端口;即所有数字,可选
(/[^\?#]*)?
匹配路径;即 /
加上可选的每个字符,直到遇到 ?
或 #
,可选地。
(\?[^#]+)?
匹配查询;即 ?
加上每个字符,直到遇到 #
,可选。
(#.*)?
匹配片段;即 #
加上后面的所有内容,可选。
编辑: 我正在使用的最终版本(添加捕获组以便更好地提取 + 丢弃 new-line 个字符):
(\w[\w\d\+\.-]*)://((.+)@)?([^:/\?#\r\n]+)(:(\d+))?(/([^\?#\r\n]*))?(\?([^#\r\n]*))?(#(.*))?
Try it online 对抗随机生成的 url。
我正在尝试编写正则表达式来提取 URL 组件。语法可以在这里找到:RFC 3986.
有些组件是可选的。到目前为止我有:
(.+)://((.*)@)?(.+?)(:(\d*))?/((.*)\?)?((.*)#)?(.*)
分解为:
(.+)://
匹配后跟://
的方案。不可选。((.*)@)?
匹配权限的用户信息部分。可选。(.+?)
匹配主机。不是可选的。这里有一个问题,这个组 也将匹配 可选端口。(:(\d*))?
应该匹配端口。/
这个和后面的所有内容都应该是可选的。((.*)\?)?
匹配路径部分。可选。((.*)#)?
匹配查询部分。可选。(.*)
匹配片段部分。可选。
我如何改进此正则表达式以使其在 RFC3986 中有效?
有趣的事实:这个正则表达式匹配自身。
示例URL(取自RFC):foo://example.com:8042/over/there?name=ferret#nose
编辑:我忘了转义d
。现在剩下要做的就是使 host 之后的所有内容成为可选的,包括领先的 /
.
如果您只转义斜线,最好也转义冒号,您的正则表达式就可以正常工作。结果是(.+)\:\/\/(.*@)?(.+?)(:(\d*))?\/((.*)\?)?((.*)#)?(.*)
。这是一个简单的脚本,展示了如何使用它来过滤掉无效的 URI:
更新 根据评论,我做了以下修改:
- 我已经添加了
(\:((\d*)\/))?(\/)*
。解释:\:((\d*)
匹配一个冒号,然后是任何数字串。- 之后的
\/
匹配一个斜杠,该斜杠应该在这串数字之后。这是因为端口不能包含任何其他字符,只能包含数字。所以在uri的port-portion中是找不到的。 - 最后,整个 port-matching 表达式是可选的,因此
?
. - 最后一部分表示 existing/non-existing 端口后可以有很多斜杠或没有斜杠
最终正则表达式:
(.+)\:\/\/(.*\@)?(.+?)(\:((\d*)\/))?(\/)*((.*)\?)?((.*)\#)?(.*)
const myRegEx = new RegExp("(.+)\:\/\/(.*\@)?(.+?)(\:((\d*)\/))?(\/)*((.*)\?)?((.*)\#)?(.*)", "g");
const allUris = [
/*Valid*/ "https://me@data.www.example.com:5050/page?query=value#element",
/*Valid*/ "foo://example.com:8042/over/there?name=ferret#nose",
/*Valid*/ "foo://example.com",
/*Not valid*/ "www.example.com"];
const allowedUris = allUris.map(uri => {
// Use the regexp to match it, then return the match
const match = uri.match(myRegEx);
return match;
});
console.log("Here are the valid URIs:");
console.log(allowedUris.join("\n\n")); // Should only print the first two URIs from the array.
我找到了一种更好的方法来处理这个问题,同时也不会破坏捕获组。
(\w[\w\d\+\.-]*)://(.+@)?([^:/\?#]+)(:\d+)?(/[^\?#]*)?(\?[^#]+)?(#.*)?
分解:
(\w[\w\d\+\.-]*)://
根据 RFC-3986 匹配有效方案。(.+@)?
匹配用户信息;即@
之前的所有内容,可选。([^:/\?#]+)
匹配主机;即,遇到:
或/
或?
或#
之前的所有内容。(:\d+)?
匹配端口;即所有数字,可选(/[^\?#]*)?
匹配路径;即/
加上可选的每个字符,直到遇到?
或#
,可选地。(\?[^#]+)?
匹配查询;即?
加上每个字符,直到遇到#
,可选。(#.*)?
匹配片段;即#
加上后面的所有内容,可选。
编辑: 我正在使用的最终版本(添加捕获组以便更好地提取 + 丢弃 new-line 个字符):
(\w[\w\d\+\.-]*)://((.+)@)?([^:/\?#\r\n]+)(:(\d+))?(/([^\?#\r\n]*))?(\?([^#\r\n]*))?(#(.*))?
Try it online 对抗随机生成的 url。