支持IDN的工具用于编码/解码可读IRI与有效URI
假设用户输入了某个资源的地址,我们需要把它转换成:
<a href="valid URI here">human readable form</a>
HTML4的规范提到了一种叫做RFC 3986的标准,这个标准只允许在主机部分使用ASCII字母数字字符和短横线,而其他部分的非ASCII字符需要用百分号编码。这就是我想放在链接的href属性里,以确保在所有浏览器中链接都能正常工作。国际化域名(IDN)需要用Punycode进行编码。
HTML5草案提到的标准是RFC 3987,这个标准也允许在主机部分使用百分号编码的Unicode字符,并且在主机和其他部分都可以使用大量的Unicode字符而不需要编码。用户可以以这些形式输入地址。为了提供人类可读的形式,我需要解码所有可打印的字符。需要注意的是,地址的某些部分可能不对应有效的UTF-8序列,通常是因为目标网站使用了其他字符编码。
我想要得到的一个例子是:
<a href="http://xn--80aswg.xn--p1ai/%D0%BF%D1%83%D1%82%D1%8C?%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81">
http://сайт.рф/путь?запрос</a>
有没有什么工具可以解决这些问题?我特别想知道Python和JavaScript的库。
更新:我知道在Python和JavaScript中有办法进行百分号和Punycode编码/解码(虽然没有进行适当的规范化,但我可以接受)。整个任务需要更多的工作,并且有一些陷阱(某些字符在特定情况下应该总是编码或从不编码)。我在想是否有现成的库可以解决整个问题,因为这似乎是一个相当常见的需求,现代浏览器已经能做到这样的转换(试着在Google Chrome中输入http://%D1%81%D0%B0%D0%B9%D1%82.%D1%80%D1%84/
,它会被替换为http://сайт.рф/
,但在HTTP请求中使用Host: xn--80aswg.xn--p1ai
)。
更新2:Vinay Sajip指出Werkzeug有处理大部分情况的iri_to_uri和uri_to_iri函数。我目前只发现了两个它处理不好的情况:百分号编码的主机(这个比较好修复)和无效的UTF-8序列(这个稍微复杂一点,但应该不成问题)。
我仍在寻找JavaScript的库。虽然写起来不难,但我更希望能避免重复造轮子。
1 个回答
如果我理解得没错的话,你可以使用Python自带的功能:
# -*- coding: utf-8 -*-
import urllib
import urlparse
URL1 = u'http://сайт.рф/путь?запрос'
URL2 = 'http://%D1%81%D0%B0%D0%B9%D1%82.%D1%80%D1%84/'
def to_idn(url):
parts = list(urlparse.urlparse(url))
parts[1] = parts[1].encode('idna')
parts[2:] = [urllib.quote(s.encode('utf-8')) for s in parts[2:]]
return urlparse.urlunparse(parts)
def from_idn(url):
return urllib.unquote(url)
print to_idn(URL1)
print from_idn(URL2)
print to_idn(from_idn(URL2).decode('utf-8'))
这段代码会输出:
http://xn--80aswg.xn--p1ai/%D0%BF%D1%83%D1%82%D1%8C?%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81
http://сайт.рф/
http://xn--80aswg.xn--p1ai/
看起来正是你想要的。我不太确定你提到的特殊情况是什么,能不能给一些你所说的陷阱的例子呢?
更新:我刚想起来,Werkzeug在0.6及以后的版本中有iri_to_uri
和uri_to_iri
这两个函数(链接指向相关文档部分)。
进一步更新:抱歉,我之前没有注意到你也在寻找JavaScript的实现。现有的公共领域的JavaScript实现punycode可以在这里找到。不过我不能保证它的可靠性。当然,你也可以使用JavaScript自带的encodeURI
/decodeURI
API。