哪些字符会使网址无效?
这些有效的网址吗?
example.com/file[/].html
http://example.com/file[/].html
哪些字符会使网址无效?
这些有效的网址吗?
example.com/file[/].html
http://example.com/file[/].html
Answers:
通常,由RFC 3986(请参见第2节:字符)定义的URI 可以包含以下84个字符中的任何一个:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=
请注意,此列表并未说明这些字符在URI中可能出现的位置。
任何其他字符都需要使用百分比编码(%
hh
)进行编码。URI的每个部分对于需要用百分比编码的单词表示哪些字符都有进一步的限制。
/^([!#$&-;=?-[]_a-z~]|%[0-9a-fA-F]{2})+$/
您是否发现它应该接受其他任何内容?(请注意,正则表达式仅检查字符串是否包含有效的URL字符,而不检查字符串是否包含格式正确的URL。)
为了进一步说明问题并直接解决上述问题,有几类字符会引起URL和URI问题。
有些字符是不允许使用的,并且永远不应出现在URL / URI中,保留字符(如下所述)和某些在某些情况下可能会引起问题的字符,但它们被标记为“不明智”或“不安全”。为何限制字符的解释在RFC-1738(URL)和RFC-2396(URI)中明确说明。请注意,较新的RFC-3986(对RFC-1738的更新)定义了在给定上下文中允许使用哪些字符的结构,但是较旧的规范对以下规则不允许使用哪些字符进行了更简单,更通用的描述。
URI语法中不允许使用的排除的US-ASCII字符:
control = <US-ASCII coded characters 00-1F and 7F hexadecimal>
space = <US-ASCII coded character 20 hexadecimal>
delims = "<" | ">" | "#" | "%" | <">
排除字符“#”是因为它用于从片段标识符中分隔URI。排除百分比字符“%”,因为它用于转义字符的编码。换句话说,“#”和“%”是必须在特定上下文中使用的保留字符。
允许使用不明智的字符列表,但可能会导致问题:
unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
在查询组件中保留的字符和/或在URI / URL中具有特殊含义的字符:
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
上面的“保留”语法类指的是URI中允许的那些字符,但是通用URI语法的特定组件中可能不允许的那些字符。并非在所有上下文中都保留“保留”集中的字符。例如,主机名可以包含可选的用户名,因此它可能类似于ftp://user@hostname/
“ @”字符具有特殊含义的地方。
这是一个URL的示例,该URL包含无效和不明智的字符(例如'$','[',']'),并且应正确编码:
http://mw1.google.com/mw-earth-vectordb/kml-samples/gp/seattle/gigapxl/$[level]/r$[y]_c$[x].jpg
URI / URL的某些字符限制取决于编程语言。例如,“ |” (0x7C)字符(尽管在URI规范中仅被标记为“不明智”)会在Java java.net.URI构造函数中引发URISyntaxException,因此,不允许使用类似URL,并且必须对其进行编码,就像将Java与URI对象实例一起使用一样。http://api.google.com/q?exp=a|b
http://api.google.com/q?exp=a%7Cb
?
只是罚款在收到查询部分,但是不可能的,而且我不认为@
属于在任何邮件列表。哦,不是%25
最后一个字符串,不是%7C
吗?
这里大多数现有的答案都是不切实际的,因为它们完全忽略了地址的实际用法,例如:
首先,离题。什么是这些地址?它们是有效的网址吗?
从历史上看,答案是“否”。根据RFC 3986,从2005年开始,此类地址不是URI(因此不是URL,因为URL 是URI的一种)。按照2005 IETF标准的术语,我们应该适当地将它们称为RFC 3987中定义的IRI(国际化资源标识符),从技术上讲,它不是URI,但只需对IRI中的所有非ASCII字符进行百分比编码,就可以将其转换为URI。 。
根据现代规范,答案是“是”。在WHATWG生活标准只是分类的一切,这在以前被称为“URI的”或“IRIS”的“网址”。这使专门术语与未阅读该规范的普通人如何使用“ URL”一词保持一致,这是该规范的目标之一。
按照“ URL”这个较新的含义,允许使用什么字符?在网址的许多部分(例如查询字符串和路径),我们允许使用任意的“ URL单位”,即
什么是“ URL代码点”?
该URL代码点是ASCII字母,U + 0021(!),U + 0024($),U + 0026(),U + 0027('),U + 0028左括号,U + 0029右括号,U + 002A(*),U + 002B(+),U + 002C(,),U + 002D(-),U + 002E(。),U + 002F(/),U + 003A(:),U + 003B (;),U + 003D(=),U + 003F(?),U + 0040(@),U + 005F(_),U + 007E(〜)和范围在U + 00A0到U之间的代码点+ 10FFFD(含),不包括替代字符和非字符。
(请注意,“ URL代码点”列表中不包含%
,但%
如果它们是百分比编码序列的一部分,则可以在“ URL代码单元”中使用。)
我可以发现的唯一规范允许使用该集中未包含的字符的地方是host,其中IPv6地址包含在[
和]
字符中。URL中的其他任何地方,都允许使用URL单元,或者使用一些甚至更具限制性的字符集。
出于历史原因,并且由于此处未在其他答案中对其进行全面探讨,因此让我们研究一下旧规范对是否允许使用。
首先,我们有两种类型的RFC 3986 保留字符:
:/?#[]@
,它们是RFC 3986中定义的URI通用语法的一部分!$&'()*+,;=
,它不是RFC通用语法的一部分,但保留用作特定URI方案的语法组件。例如,分号和逗号被用作的语法的一部分的数据的URI,并&
和=
被用作普遍存在的一部分?foo=bar&qux=baz
在查询字符串格式(其未由RFC 3986规定)。上面的任何保留字符都可以合法地在URI中使用,而无需进行编码,以达到其语法目的,或者在某些地方不能将其用作数据中的文字字符,而这些地方不能被误解为具有其语法目的的字符。(例如,尽管/
URL中具有语法含义,但是您可以在查询字符串中使用未编码的语法,因为它在查询字符串中没有含义。)
RFC 3986还指定了一些未保留的字符,这些字符始终可以简单地用于表示数据而无需任何编码:
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~
最后,%
允许字符本身进行百分比编码。
这样只剩下以下禁止在URL中出现的ASCII字符:
"<>\^`{|}
ASCII中的所有其他字符都可以合法地出现在URL中。
然后,RFC 3987使用以下unicode字符范围扩展了该保留字符集:
%xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
/ %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
/ %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
/ %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
/ %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
/ %xD0000-DFFFD / %xE1000-EFFFD
考虑到最新的Unicode 块定义,从旧规范中选择这些块似乎很奇怪和任意;这可能是因为自编写RFC 3987以来的十年中已添加了这些块。
最后,也许值得一提的是,仅仅知道哪些字符可以合法出现在URL中还不足以识别某些给定的字符串是否为合法URL,因为某些字符仅在URL的特定部分才是合法的。例如,保留字符[
和]
是合法的,可以作为URL中IPv6文字主机的一部分,例如http:// [1080 :: 8:800:200C:417A] / foo,但在任何其他上下文中都不合法,因此OP的示例http://example.com/file[/].html
是非法的。
在补充问题中,您询问是否www.example.com/file[/].html
有效的URL。
该URL无效,因为URL是URI的一种,并且有效URI必须具有类似的方案http:
(请参阅RFC 3986)。
如果您想询问是否http://www.example.com/file[/].html
有效的URL,那么答案仍然是否,因为方括号字符在那里无效。
方括号字符为URL保留以下格式:(http://[2001:db8:85a3::8a2e:370:7334]/foo/bar
即IPv6文字而不是主机名)
如果您想完全理解此问题,则值得仔细阅读RFC 3986。
Unwise
非常重视URI,但可以使用URL库。那是没有可忽略的标志Unwise
。我将不得不检查URL的Rust lang(因为它是为浏览器构建的,我很好奇它的作用)。不过,大多数浏览器也会愉快地传递“ [”,“]”。因此,从理论上讲,就像我对C / C ++所说的那样,它们是sub / super,但现实并非如此。它高度依赖于super / subset的规范和语义的解释。
RFC 3986中定义了可以在URI(URL是URI的一种类型)中使用的所有有效字符。
如果其他所有字符都先经过“ URL编码”,则可以在URL中使用。这涉及更改特定“代码”的无效字符(通常以百分比符号(%)的形式,后跟十六进制数字)。
HTML URL编码参考此链接包含无效字符的编码列表。
几个Unicode字符范围是有效的HTML5,尽管使用它们可能仍然不是一个好主意。
例如,href
文档说http://www.w3.org/TR/html5/links.html#attr-hyperlink-href:
和元素上的href属性必须具有一个值,该值是一个有效的URL,可能被空格包围。
然后,“有效URL”的定义指向http://url.spec.whatwg.org/,其目的是:
使RFC 3986和RFC 3987与现代实现保持一致,并在此过程中将其淘汰。
该文档将URL代码点定义为:
ASCII字母数字,“!”,“ $”,“&”,“'”,“(”,“)”,“ *”,“ +”,“,”,“-”,“。”,“ /” ,“:”,“;”,“ =”,“?”,“ @”,“ _”,“〜”和代码点,范围为U + 00A0至U + D7FF,U + E000至U + FDCF ,U + FDF0至U + FFFD,U + 10000至U + 1FFFD,U + 20000至U + 2FFFD,U + 30000至U + 3FFFD,U + 40000至U + 4FFFD,U + 50000至U + 5FFFD,U +60000至U + 6FFFD,U + 70000至U + 7FFFD,U + 80000至U + 8FFFD,U + 90000至U + 9FFFD,U + A0000至U + AFFFD,U + B0000至U + BFFFD,U + C0000到U + CFFFD,U + D0000到U + DFFFD,U + E1000到U + EFFFD,U + F0000到U + FFFFD,U + 100000到U + 10FFFD。
语句中使用了术语“ URL代码点”:
如果c不是URL代码点,也不是“%”,则分析错误。
在解析算法的几个部分中,包括架构,权限,相对路径,查询和片段状态:因此基本上是整个URL。
另外,验证器http://validator.w3.org/传递URL,如"你好"
,而不传递URL字符,如空格"a b"
当然,正如Stephen C提到的,它不仅与字符有关,而且与上下文有关:您必须了解整个算法。但是,由于在算法的关键点上使用了“ URL代码点”类,因此可以很好地了解您可以使用或不使用什么。
另请参阅:URL中的Unicode字符
我需要选择字符以将URL拆分为字符串,因此我决定创建一个自己无法在URL中找到的字符列表:
>>> allowed = "-_.~!*'();:@&=+$,/?%#[]?@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
>>> from string import printable
>>> ''.join(set(printable).difference(set(allowed)))
'`" <\x0b\n\r\x0c\\\t{^}|>'
因此,可能的选择是换行符,制表符,空格,反斜杠和"<>{}^|
。我想我会选择空格或换行符。:)
并不是真正回答您的问题,但验证url确实是一个严重的问题。您最好验证域名,并将查询的一部分留在url中。那是我的经验。您还可以通过ping通URL并查看它是否导致有效的响应,但是对于这样一个简单的任务而言,可能太多了。
用于检测网址的正则表达式非常丰富,请在Google上添加:)
我想出了一些PHP的正则表达式,可以将文本中的URL转换为锚标记。(首先,它将所有www。网址转换为http://,然后将所有带有https?://的网址转换为href = ... html链接
$string = preg_replace('/(https?:\/\/)([!#$&-;=?\-\[\]_a-z~%]+)/sim', '<a href="$1$2">$2</a>',
preg_replace('/(\s)((www\.)([!#$&-;=?\-\[\]_a-z~%]+))/sim', '$1http://$2', $string)
);