如何在python中取消引用urlencoded unicode字符串?
Posted
技术标签:
【中文标题】如何在python中取消引用urlencoded unicode字符串?【英文标题】:How to unquote a urlencoded unicode string in python? 【发布时间】:2010-09-22 23:04:37 【问题描述】:我有一个像“Tanım”这样的 unicode 字符串,它以某种方式编码为“Tan%u0131m”。如何将此编码字符串转换回原始 unicode。 显然 urllib.unquote 不支持 unicode。
【问题讨论】:
【参考方案1】:%uXXXX 是一个被 w3c 拒绝的non-standard encoding scheme,尽管一个实现仍然存在于 javascript 领域。
更常见的技术似乎是对字符串进行 UTF-8 编码,然后使用 %XX 对结果字节进行 % 转义。 urllib.unquote 支持此方案:
>>> urllib2.unquote("%0a")
'\n'
不幸的是,如果你真的需要支持 %uXXXX,你可能不得不推出自己的解码器。否则,可能更可取的是简单地对您的 unicode 进行 UTF-8 编码,然后对结果字节进行 % 转义。
一个更完整的例子:
>>> u"Tanım"
u'Tan\u0131m'
>>> url = urllib.quote(u"Tanım".encode('utf8'))
>>> urllib.unquote(url).decode('utf8')
u'Tan\u0131m'
【讨论】:
'urllib2.unquote' 应该是 'urllib.unquote' 有趣的是 URI 是百分比编码的字节字符串,而不是字符串。 @jamtoday 没必要,在 Python 2.7.5+ 中你可以使用urllib2.unquote
试试print(dir(urllib2))
urllib.unquote(url.encode('utf-8')) 代替我工作
像unquote(urlencode())
这样的做法是不好的做法吗?【参考方案2】:
def unquote(text):
def unicode_unquoter(match):
return unichr(int(match.group(1),16))
return re.sub(r'%u([0-9a-fA-F]4)',unicode_unquoter,text)
【讨论】:
这仅适用于 Python 2,不幸的是,它是 rapidly approaching its end-of-life。要使这个 Python 2 和 3 兼容(try: unichr
、except NameError: unichr = chr
)并不难纠正,但这个版本不处理代理对。 %hhhh
转义格式的目的是编码 UTF-16 代码点,因此对于非 BMP 序列(例如大量表情符号),除了 a UCS-2 Python 2 构建。【参考方案3】:
如果你绝对必须拥有它,它会这样做(我真的同意“非标准”的呼声):
from urllib import unquote
def unquote_u(source):
result = unquote(source)
if '%u' in result:
result = result.replace('%u','\\u').decode('unicode_escape')
return result
print unquote_u('Tan%u0131m')
> Tanım
【讨论】:
有点病态的情况,但是:unquote_u('Tan%25u0131m') --> u'Tan\u0131m' 而不是 'Tan%u0131' 应该的。只是提醒你为什么除非你真的需要它,否则你可能不想编写解码器。 我完全同意。这就是为什么我真的不热衷于提供一个实际的解决方案。这些事情从未如此简单。不过,OP 可能已经绝望了,我认为这补充了您的出色答案。 这仅适用于 Python 2,不幸的是,它是 rapidly approaching its end-of-life。unicode_escape
的使用使 Python 3 的使用更难更正(您需要先编码为 utf-8),但此版本不处理代理对。 %hhhh
转义格式的目的是编码 UTF-16 代码点,因此对于非 BMP 序列(例如大量表情符号),除了 a UCS-2 Python 2 构建。【参考方案4】:
上述版本中存在一个错误,当字符串中同时存在 ascii 编码和 unicode 编码字符时,有时会出现异常。我认为它特别适用于除了 unicode 之外还有 '\xab' 等高 128 范围内的字符。
例如。 "%5B%AB%u03E1%BB%5D" 会导致此错误。
我发现如果你先做 unicode,问题就消失了:
def unquote_u(source):
result = source
if '%u' in result:
result = result.replace('%u','\\u').decode('unicode_escape')
result = unquote(result)
return result
【讨论】:
\xab 不是字符而是字节。实际上,您的示例“字符串”同时包含字节和字符,这在我所知道的任何语言中作为单个字符串都是无效的。"%5B%AB%u03E1%BB%5D"
解码为什么? 0x5B 0xAB 和 0xBB 0x5D 几乎不是有效的 UTF-8 序列。
@wberry:我见过将一些 ASCII 码点(例如空格)编码为 %hh
序列的真实案例(某处的 Java 库),以及将超过 0x7F 的任何内容编码为 %uhhhh
序列。糟糕,但可以解析。【参考方案5】:
您有一个使用 non-standard encoding scheme 的 URL,被标准机构拒绝,但仍由某些编码器生成。 Python urllib.parse.unquote()
函数无法处理这些。
幸运的是,创建自己的解码器并不难。 %uhhhh
条目在这里是 UTF-16 代码点,因此我们需要考虑 surrogate pairs。我还看到混入了%hh
代码点,以增加混淆。
考虑到这一点,这里有一个可在 Python 2 和 Python 3 中工作的解码器,前提是您在 Python 3 中传入 str
对象(Python 2 不太关心):
try:
# Python 3
from urllib.parse import unquote
unichr = chr
except ImportError:
# Python 2
from urllib import unquote
def unquote_unicode(string, _cache=):
string = unquote(string) # handle two-digit %hh components first
parts = string.split(u'%u')
if len(parts) == 1:
return parts
r = [parts[0]]
append = r.append
for part in parts[1:]:
try:
digits = part[:4].lower()
if len(digits) < 4:
raise ValueError
ch = _cache.get(digits)
if ch is None:
ch = _cache[digits] = unichr(int(digits, 16))
if (
not r[-1] and
u'\uDC00' <= ch <= u'\uDFFF' and
u'\uD800' <= r[-2] <= u'\uDBFF'
):
# UTF-16 surrogate pair, replace with single non-BMP codepoint
r[-2] = (r[-2] + ch).encode(
'utf-16', 'surrogatepass').decode('utf-16')
else:
append(ch)
append(part[4:])
except ValueError:
append(u'%u')
append(part)
return u''.join(r)
该函数深受current standard-library implementation 的启发。
演示:
>>> print(unquote_unicode('Tan%u0131m'))
Tanım
>>> print(unquote_unicode('%u05D0%u05D9%u05DA%20%u05DE%u05DE%u05D9%u05E8%u05D9%u05DD%20%u05D0%u05EA%20%u05D4%u05D8%u05E7%u05E1%u05D8%20%u05D4%u05D6%u05D4'))
איך ממירים את הטקסט הזה
>>> print(unquote_unicode('%ud83c%udfd6')) # surrogate pair
?
>>> print(unquote_unicode('%ufoobar%u666')) # incomplete
%ufoobar%u666
该函数适用于 Python 2(在 2.4 - 2.7 上测试)和 Python 3(在 3.3 - 3.8 上测试)。
【讨论】:
以上是关于如何在python中取消引用urlencoded unicode字符串?的主要内容,如果未能解决你的问题,请参考以下文章
如何在kivymd python的MDDataTable中以编程方式取消选中复选框