我看了一遍,还没有找到一个解决方案,以满足我对正常表达式模式的需求,该模式将匹配通用URL。我需要支持多种协议(带验证),localhost和/或IP寻址,端口和查询字符串。一些例子:
理想情况下,我希望该模式也支持提取各种元素(协议,主机,端口,查询字符串等),但这不是必需的。
(另外,出于我和未来读者的目的,如果你能解释这种模式,那将会有所帮助。)
答案 0 :(得分:5)
RFC 3986/STD 0066的附录B(统一资源标识符(URI):通用语法)提供了您需要的正则表达式:
附录B.使用正则表达式解析URI引用
由于“第一场比赛胜利”算法与“贪婪”相同 POSIX正则表达式使用的消歧方法,它是 自然而普通的使用正则表达式来解析 URI引用的潜在五个组件。
以下行是用于分解a的正则表达式 格式良好的URI引用到其组件中。
^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? 12 3 4 5 6 7 8 9
上面第二行中的数字只是为了提高可读性; 它们表示每个子表达的参考点(即每个子表达式) 配对括号)。我们引用子表达式匹配的值
匹配<n>
为$<n>
。例如,将上述表达式与http://www.ics.uci.edu/pub/ietf/uri/#Related
导致以下子表达式匹配:
$1 = http: $2 = http $3 = //www.ics.uci.edu $4 = www.ics.uci.edu $5 = /pub/ietf/uri/ $6 = <undefined> $7 = <undefined> $8 = #Related $9 = Related
其中
<undefined>
表示组件不存在,原样 上例中查询组件的情况。因此,我们 可以确定五个组件的值scheme = $2 authority = $4 path = $5 query = $7 fragment = $9
反方向,我们可以从中重新创建URI引用 其组件使用5.3节的算法。
至于验证针对特定方案的URI,您需要查看描述您有兴趣获取所需详细信息的方案的RFC。验证URI对于它声称的方案是否有效。 URI方案注册表位于http://www.iana.org/assignments/uri-schemes.html。
即便如此,你注定会遇到某种失败。考虑file:
方案。您无法验证它是否代表authority
文件系统中的有效路径(除非您是权限)。您可以做的最好的事情是验证它表示看起来像有效路径的东西。即便如此,一个Windows文件:像file:///C:/foo/bar/baz/bat.txt
这样的网址(除了运行某种Windows的服务器)之外的任何东西都是无效的。运行* nix的任何服务器都可能会阻塞它(无论如何,驱动器号是什么?)。
答案 1 :(得分:2)
Nicholas Carey引导您走向RFC-3986是正确的。他指出的正则表达式将匹配一个通用URI,但它不会验证它(并且这个正则表达式不适合从“野外”中选择网址 - 它太松散并且几乎与任何匹配包含空字符串的字符串)。
关于验证要求,您可能需要查看我在该主题上撰写的文章,该文章从附录A中获取了所有各种组件的所有ABNF语法定义,并提供了正则表达式等价物:
Regular Expression URI Validation
关于从“狂野”中挑选URL的主题,请查看Jeff Atwood的“The Problem With URLs”和John'Gruber的“An Improved Liberal, Accurate Regex Pattern for Matching URLs”博客文章,了解一些可能出现的微妙问题。另外,您可能想看看我去年开始的项目:URL Linkification - 这会从已经有一些链接的文本中挑选出未链接的HTTP和FTP URL。
也就是说,以下是一个PHP函数,它使用RFC-3986“绝对URI”正则表达式的略微修改版本来验证HTTP和FTP URL(使用此正则表达式,命名为 host 部分一定不能空着。 URI的所有各种组件都被隔离并捕获到命名组中,这样可以轻松地操作和验证程序代码中的各个部分:
function url_valid($url)
{
if (strpos($url, 'www.') === 0) $url = 'http://'. $url;
if (strpos($url, 'ftp.') === 0) $url = 'ftp://'. $url;
if (!preg_match('/# Valid absolute URI having a non-empty, valid DNS host.
^
(?P<scheme>[A-Za-z][A-Za-z0-9+\-.]*):\/\/
(?P<authority>
(?:(?P<userinfo>(?:[A-Za-z0-9\-._~!$&\'()*+,;=:]|%[0-9A-Fa-f]{2})*)@)?
(?P<host>
(?P<IP_literal>
\[
(?:
(?P<IPV6address>
(?: (?:[0-9A-Fa-f]{1,4}:){6}
| ::(?:[0-9A-Fa-f]{1,4}:){5}
| (?: [0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}
| (?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}
| (?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}
| (?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?:: [0-9A-Fa-f]{1,4}:
| (?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::
)
(?P<ls32>[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}
| (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}
(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)
)
| (?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?:: [0-9A-Fa-f]{1,4}
| (?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::
)
| (?P<IPvFuture>[Vv][0-9A-Fa-f]+\.[A-Za-z0-9\-._~!$&\'()*+,;=:]+)
)
\]
)
| (?P<IPv4address>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}
(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))
| (?P<regname>(?:[A-Za-z0-9\-._~!$&\'()*+,;=]|%[0-9A-Fa-f]{2})+)
)
(?::(?P<port>[0-9]*))?
)
(?P<path_abempty>(?:\/(?:[A-Za-z0-9\-._~!$&\'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)
(?:\?(?P<query> (?:[A-Za-z0-9\-._~!$&\'()*+,;=:@\\/?]|%[0-9A-Fa-f]{2})*))?
(?:\#(?P<fragment> (?:[A-Za-z0-9\-._~!$&\'()*+,;=:@\\/?]|%[0-9A-Fa-f]{2})*))?
$
/mx', $url, $m)) return FALSE;
switch ($m['scheme'])
{
case 'https':
case 'http':
if ($m['userinfo']) return FALSE; // HTTP scheme does not allow userinfo.
break;
case 'ftps':
case 'ftp':
break;
default:
return FALSE; // Unrecognised URI scheme. Default to FALSE.
}
// Validate host name conforms to DNS "dot-separated-parts".
if ($m{'regname'}) // If host regname specified, check for DNS conformance.
{
if (!preg_match('/# HTTP DNS host name.
^ # Anchor to beginning of string.
(?!.{256}) # Overall host length is less than 256 chars.
(?: # Group dot separated host part alternatives.
[0-9A-Za-z]\. # Either a single alphanum followed by dot
| # or... part has more than one char (63 chars max).
[0-9A-Za-z] # Part first char is alphanum (no dash).
[\-0-9A-Za-z]{0,61} # Internal chars are alphanum plus dash.
[0-9A-Za-z] # Part last char is alphanum (no dash).
\. # Each part followed by literal dot.
)* # One or more parts before top level domain.
(?: # Explicitly specify top level domains.
com|edu|gov|int|mil|net|org|biz|
info|name|pro|aero|coop|museum|
asia|cat|jobs|mobi|tel|travel|
[A-Za-z]{2}) # Country codes are exqactly two alpha chars.
$ # Anchor to end of string.
/ix', $m['host'])) return FALSE;
}
$m['url'] = $url;
for ($i = 0; isset($m[$i]); ++$i) unset($m[$i]);
return $m; // return TRUE == array of useful named $matches plus the valid $url.
}
第一个正则表达式将字符串验证为绝对(具有非空主机部分)通用URI。第二个正则表达式用于验证关于DNS查找系统的(命名的)主机部分(当它不是IP文字或IPv4地址时)(其中每个以点分隔的子域为63个字符或由数字,字母和短划线组成,总长度小于255个字符。)
请注意,此功能的结构允许轻松扩展以包含其他方案。
答案 2 :(得分:0)
这有可能是Perl吗?
尝试:
use strict;
my $url = "http://localhost/test";
if ($url =~ m/^(.+):\/\/(.+)\/(.+)/) {
my $protocol = $1;
my $domain = $2;
my $dir = $3;
print "$protocol $domain $dir \n";
}