首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >在Python 3中将Unicode转换为ASCII

在Python 3中将Unicode转换为ASCII
EN

Stack Overflow用户
提问于 2021-03-20 01:44:39
回答 2查看 544关注 0票数 1

我已经尝试了许多解决方案,我已经阅读了许多网站,但我似乎无法解决这个问题。我有一个包含消息对象的文件。每条消息都有一个4字节值,即消息类型,一个4字节值,即长度,然后是消息数据,即Unicode中的ASCII。当我打印到屏幕上时,它看起来像ASCII。当我将输出定向到一个文件时,我得到了Unicode,所以我试图解码所有这些内容的方式有些不对劲。以下是python脚本:

代码语言:javascript
代码运行次数:0
运行
复制
import sys
import codecs
import encodings.idna
import unicodedata

def getHeader(fileObj):
    mstype_array = bytearray(4)
    mslen_array = bytearray(4)
    mstype = 0
    mslen = 0
    fileObj.seek(-1, 1)
    mstype_array = fileObj.read(4)
    mslen_array = fileObj.read(4)
    mstype = int.from_bytes(mstype_array, byteorder=sys.byteorder)
    mslen = int.from_bytes(mslen_array, byteorder=sys.byteorder)
    return mstype,mslen

def getMessage(fileObj, count):
    str = fileObj.read(count)#.decode("utf-8", "strict")
    return str

def getFields(msg):
    msg = codecs.decode(msg, 'utf-8')
    fields = msg.split(';')
    return fields

mstype = 0
mslen = 0
with open('../putty.log', 'rb') as f:
    while True:
        byte = f.read(1)
        if not byte:
            break
        if byte == b'\x1D':
            mstype, mslen = getHeader(f)
            print (f"Msg Type: {mstype} Msg Len: {mslen}")
            msg = getMessage(f, mslen)
            print(f"Message: {codecs.decode(msg, 'utf-8')}")
            #print(type(msg))
            fields = getFields(msg)
            print("Fields:")
            for field in fields:
                print(field)
        else:
            print (f"Char read: {byte}  {hex(ord(byte))}")

用户可以使用此link获取要解码的文件。

EN

回答 2

Stack Overflow用户

发布于 2021-03-20 03:06:11

在写入控制台和写入文件时,sys.stdout的行为似乎有所不同。手册(https://docs.python.org/3/library/sys.html#sys.stdout)说这是意料之中的,但只给出了Windows的细节。

在任何情况下,您都要将unicode写入标准输出(通过print()),这就是在文件中获取unicode的原因。可以通过不对getFields中的消息进行解码来避免这种情况(因此可以用fields = msg.split(b';')替换fields = getFields(msg),并使用sys.stdout.buffer.write(field+b'\n')写入标准输出。

显然,混合使用print()sys.stdout.buffer.write()存在一些问题,因此Python 3: write binary to stdout respecting buffering可能值得一读。

tl;dr -尝试在完全不解码为unicode的情况下写入字节。

票数 1
EN

Stack Overflow用户

发布于 2021-03-20 03:22:59

简而言之,定义一个自定义函数,并在调用print的任何地方使用它。

代码语言:javascript
代码运行次数:0
运行
复制
import sys

def ascii_print(txt):
    sys.stdout.buffer.write(txt.encode('ascii', errors='backslashreplace'))

ASCII是utf-8的一个子集。ACSII字符与相同的utf-8编码字符无法区分。在内部,所有Python字符串都是原始Unicode。但是,原始Unicode不能读入或写出。必须先将它们编码为某种编码。默认情况下,在大多数系统上,默认编码是utf-8,这是最常见的Unicode编码标准。

如果要使用不同的编码写出,则必须指定该编码。我假设您出于某种原因需要ascii编码。

请注意,print的文档说明:

由于打印的参数被转换为文本字符串,因此print()不能与二进制模式文件对象一起使用。对于这些,请改用file.write(...)

现在,如果您要重定向stdout,可以直接在sys.stdout中调用write()。然而,正如文档所解释的那样:

要在标准流中写入或读取二进制数据,请使用底层的二进制buffer对象。例如,要将字节写入stdout,请使用sys.stdout.buffer.write(b'abc')

因此,您可以这样做,而不是print(f"Message: {codecs.decode(msg, 'utf-8')}")行:

代码语言:javascript
代码运行次数:0
运行
复制
ascii_msg = f"Message: {codecs.decode(msg, 'utf-8')}".encode('ascii')
sys.stdout.buffer.write(ascii_msg)

请注意,我专门对字符串调用了str.encode,并显式设置了ascii编码。还要注意,我编码了整个字符串(包括Message: ),而不仅仅是传入的变量(它仍然需要解码)。然后,您需要将该ASCII编码的字节字符串直接写入sys.stdout.buffer,如第二行所示。

这样做的一个问题是,输入可能包含一些非ASCII字符。如果是这样,就会发生Unicodeerror,程序就会崩溃。为了避免这种情况,str.encode支持一些不同的错误处理选项:

其他可能的值包括'ignore''replace''xmlcharrefreplace''backslashreplace'和通过codecs.register_error()注册的任何其他名称。

由于目标输出是纯文本,因此'backslashreplace'可能是保持无损输出的最佳方法。但是,如果您不关心保留非ASCII码字符,'ignore'也可以工作。

代码语言:javascript
代码运行次数:0
运行
复制
ascii_msg = f"Message: {codecs.decode(msg, 'utf-8')}".encode('ascii', errors='backslashreplace')
sys.stdout.buffer.write(ascii_msg)

是的,对于发送到print的每个字符串,您都需要这样做。定义一个自定义的打印函数来保持代码的可读性可能是有意义的:

代码语言:javascript
代码运行次数:0
运行
复制
def ascii_print(txt):
    sys.stdout.buffer.write(txt.encode('ascii', errors='backslashreplace'))

然后在你的代码中,你可以直接调用它,而不是print

代码语言:javascript
代码运行次数:0
运行
复制
ascii_print(f"Message: {codecs.decode(msg, 'utf-8')}")
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66713175

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档