【问题标题】:base64 encoding unicode strings in python 2.7python 2.7中的base64编码unicode字符串
【发布时间】:2026-02-10 20:15:01
【问题描述】:

我有一个使用 requests module 从 web 服务检索到的 unicode 字符串,其中包含二进制文档的字节(PCL,碰巧)。其中一个字节的值为 248,尝试对其进行 base64 编码会导致以下错误:

In [68]: base64.b64encode(response_dict['content']+'\n')
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
C:\...\<ipython-input-68-8c1f1913eb52> in <module>()
----> 1 base64.b64encode(response_dict['content']+'\n')

C:\Python27\Lib\base64.pyc in b64encode(s, altchars)
     51     """
     52     # Strip off the trailing newline
---> 53     encoded = binascii.b2a_base64(s)[:-1]
     54     if altchars is not None:
     55         return _translate(encoded, {'+': altchars[0], '/': altchars[1]})

UnicodeEncodeError: 'ascii' codec can't encode character u'\xf8' in position 272: ordinal not in range(128)

In [69]: response_dict['content'].encode('base64')
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
C:\...\<ipython-input-69-7fd349f35f04> in <module>()
----> 1 response_dict['content'].encode('base64')

C:\...\base64_codec.pyc in base64_encode(input, errors)
     22     """
     23     assert errors == 'strict'
---> 24     output = base64.encodestring(input)
     25     return (output, len(input))
     26

C:\Python27\Lib\base64.pyc in encodestring(s)
    313     for i in range(0, len(s), MAXBINSIZE):
    314         chunk = s[i : i + MAXBINSIZE]
--> 315         pieces.append(binascii.b2a_base64(chunk))
    316     return "".join(pieces)
    317

UnicodeEncodeError: 'ascii' codec can't encode character u'\xf8' in position 44: ordinal not in range(128)

我觉得这有点令人惊讶,因为 248 在无符号字节的范围内(并且可以保存在字节字符串中),但我真正的问题是:什么是最好或正确的方法来编码这个字符串?

我目前的解决方法是:

In [74]: byte_string = ''.join(map(compose(chr, ord), response_dict['content']))

In [75]: byte_string[272]
Out[75]: '\xf8'

这似乎可以正常工作,并且生成的 byte_string 能够进行 base64 编码,但似乎应该有更好的方法。有吗?

【问题讨论】:

  • 248 可能在无符号字节范围内,但不在标准化 ASCII [0-127] 范围内。
  • @Cameron:一个正确的观点,但它仍然不能解释问题,因为完全相同的值,当保存在字节字符串中时不会导致该错误。
  • 查看我的答案 :-) 您所做的是获取 unicode 字符串的代码点并将它们视为字节。这……充其量是可疑的,因为您无法保证代码点甚至在 0-255 范围内。更糟糕的是,以后没有其他人会知道如何解释字节字符串,因为它是在自定义的、未定义的编码中。
  • @Cameron:重申一下:这些数据不是字符代码点,它们是二进制数据。

标签: python character-encoding base64 unicode-string python-unicode


【解决方案1】:

你有一个unicode 字符串,你想对它进行base64 编码。问题是b64encode() 仅适用于字节,而不适用于字符。因此,您需要将您的 unicode 字符串(这是一个抽象的 Unicode 代码点序列)转换为一个字节字符串。

将抽象的 Unicode 字符串映射到具体的字节序列称为编码。 Python 支持多种编码;我建议使用广泛使用的 UTF-8 编码:

byte_string = response_dict['content'].encode('utf-8')

请注意,解码字节的人还需要知道使用哪种编码通过互补的decode() 函数取回unicode 字符串:

# Decode
decoded = byte_string.decode('utf-8')

了解更多关于 Unicode 和编码的良好起点是 Joel Spolsky 的 Python docsthis article

【讨论】:

  • 要明确:我的 unicode 字符串的内容是二进制数据。我无法将它们更改为一些不同的字节。有身份编码吗?
  • @Marcin:你不能有一个包含二进制数据的unicode 字符串。这是一个自相矛盾的说法!如果unicode 字符串的字节应该表示二进制数据(这里似乎就是这种情况),那么它不应该存储在unicode 对象中,因为它根本不是真正的 Unicode!
  • 为什么不添加BOM?实际上,此功能有助于检测字符串是否为 UTF-8。
  • @sebix:我认为最好通常只在文件开头使用 BOM;必须在各处检查 BOM 字符串的开销和复杂性似乎太高了。不过,我把编码弄混了,-sig 一个确实添加了 BOM。
【解决方案2】:

由于您使用的是二进制数据,我不确定使用 utf-8 编码是否是个好主意。我想这取决于您打算如何使用 base64 编码表示。我认为如果您可以将数据作为字节字符串而不是 unicode 字符串检索可能会更好。我从未使用过 requests 库,但浏览文档表明这是可能的。有部分讨论“二进制响应内容”和“原始响应内容”。

【讨论】:

  • 谢谢!事实证明,编码为 latin-1 产生的字节序列与我的解决方法完全相同。
  • @Marcin:您需要确保 requests 模块没有假定您正在处理文本、应用默认编码并将二进制数据解码为 un​​icode。如果是这样,你就有麻烦了。您能否验证内容是否符合您的预期?
  • 对文档多加注意后,事实证明 requests 还告诉我用于解码对 unicode 的响应的编码,因此我总是可以可靠地重新编码(并且再次产生相同的字节)。
【解决方案3】:

如果是二进制数据...为什么要编码/解码?特别是“base64.encodestring”部分。下面是我如何将图像编码为 base64 以直接添加到我的 python 代码中,而不是使用额外的文件。 2.7.2 顺便说一句

import base64
iconfile = open("blah.icon","rb")
icondata = iconfile.read()
icondata = base64.b64encode(icondata)

【讨论】:

    【解决方案4】:

    应该可以将响应作为二进制字节获取并完全跳过解码和编码步骤。 requests 总是有可能选择在往返过程中丢失一些数据或错误的编码。

    这部分名为"Binary Response Content" 的文档似乎非常适合您的问题。

    【讨论】:

      【解决方案5】:

      我建议在 base64 编码之前先将其编码为 UTF-8 之类的东西:

      In [12]: my_unicode = u'\xf8'
      
      In [13]: my_utf8 = my_unicode.encode('utf-8')
      
      In [15]: base64.b64encode(my_utf8)
      Out[15]: 'w7g='
      

      【讨论】:

      • 编码为 UTF-8 没有意义。您可以从 UTF-8 编码为字节/ascii,也可以从 ascii 解码为 UTF-8。反之亦然。