如何在Python 3中转换字节和字符串?

84

这是一个Python 101类型的问题,但当我尝试使用一个似乎将我的字符串输入转换为字节的包时,它曾经让我困惑了一段时间。

如下所示,我自己找到了答案,但由于花费了我很长时间才弄清楚发生了什么,我觉得记录在这里是值得的。这似乎是Python 3通用的问题,因此我没有提及我正在使用的原始包;这似乎不是错误(只是这个特定的包有一个.tostring()方法,很明显它并没有产生我理解的字符串...)

我的测试程序是这样的:

import mangler                                 # spoof package

stringThing = """
<Doc>
    <Greeting>Hello World</Greeting>
    <Greeting>你好</Greeting>
</Doc>
"""

# print out the input
print('This is the string input:')
print(stringThing)

# now make the string into bytes
bytesThing = mangler.tostring(stringThing)    # pseudo-code again

# now print it out
print('\nThis is the bytes output:')
print(bytesThing)

这段代码的输出如下:

This is the string input:

<Doc>
    <Greeting>Hello World</Greeting>
    <Greeting>你好</Greeting>
</Doc>


This is the bytes output:
b'\n<Doc>\n    <Greeting>Hello World</Greeting>\n    <Greeting>\xe4\xbd\xa0\xe5\xa5\xbd</Greeting>\n</Doc>\n'
因此,有必要能够在字节和字符串之间进行转换,以避免非ASCII字符被转换成乱码。
所需翻译内容:

So, there is a need to be able to convert between bytes and strings, to avoid ending up with non-ascii characters being turned into gobbledegook.


1
这个问题在 Stack Overflow 的答案中有更多详细的内容,但我认为下面简要的回答更清晰明了。 - Bobble
4个回答

120

以上代码示例中的“mangler”相当于执行了以下操作:

bytesThing = stringThing.encode(encoding='UTF-8')

还有其他的写法(特别是使用 bytes(stringThing, encoding='UTF-8')),但上面的语法可以清晰地表明正在发生什么,以及如何恢复字符串:

newStringThing = bytesThing.decode(encoding='UTF-8')
当我们这样做时,原始字符串将被恢复。
请注意,使用str(bytesThing)只是抄写了所有的乱码,而不会将其转换回Unicode,除非您明确要求UTF-8,即str(bytesThing, encoding='UTF-8')。如果未指定编码,则不会报告错误。

如果您查看实际的方法实现,您会发现utf-8是默认编码,因此,如果您知道编码确实是utf-8,那么您可以省略它,即stringThing.encode()bytesThing.decode()将完美地完成任务。 - ccpizza
@ccpizza 在上面的示例中明确指定编码方式可以更清楚地了解正在发生的事情,我认为这是一个好习惯。并非所有Unicode都是UTF-8。这也避免了最后一段提到的静默失败。 - Bobble
完全同意;显式优于隐式,但在我看来,了解隐式的内容也是很好的。是否使用它是另一个问题。仅仅因为你可以这样做,并不意味着你应该这样做 :) - ccpizza
在Python 3中,更安全的做法是使用decode('utf-8', 'backslashreplace')来避免在编码未知时引发异常。我们不应总是假设使用UTF-8! - Nagev

18
在Python3中,有一个与encode()格式相同的bytes()方法。
str1 = b'hello world'
str2 = bytes("hello world", encoding="UTF-8")
print(str1 == str2) # Returns True

我在文档中没有看到相关内容,但可能是我没有找对地方。这种方式可以将字符串明确转换为字节流,并且比使用encodedecode更易于阅读,而且不需要在引号前加上b前缀。


5
这是一个Python 101类型的问题,虽然问题很简单,但答案却不那么简单。
在Python3中,“bytes”对象表示一系列字节,“string”对象表示一系列Unicode代码点。要从“bytes”转换为“string”,或者从“string”转换回“bytes”,您需要使用“bytes.decode”和“string.encode”函数。这些函数接受两个参数:编码和错误处理策略。
不幸的是,有很多情况下,字节序列用于表示文本,但并没有明确定义使用的编码方式。例如,在类Unix系统上的文件名,就内核而言,它们是一系列带有少量特殊值的字节,但在大多数现代发行版上,大多数文件名将是UTF-8,但不能保证所有文件名都是如此。
如果您想编写健壮的软件,那么您需要仔细考虑这些参数。您需要仔细考虑字节应该采用哪种编码方式,以及当它们最终不是您认为应该采用的编码时,您将如何处理这种情况。Python默认为UTF-8,并对任何无效的UTF-8字节序列报错。
Python使用“repr”作为字符串的后备转换。repr尝试生成可以重新创建对象的Python代码。对于字节对象,这意味着在可打印ASCII范围之外转义字节,等等。

print(bytesThing)


3

试一下这个:

StringVariable=ByteVariable.decode('UTF-8','ignore')

测试类型:

print(type(StringVariable))

这里的 'StringVariable' 表示字符串。'ByteVariable' 表示字节。这与问题变量无关。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接