首页 > 解决方案 > 如何写入与打印格式相同的文件?

问题描述

TL;博士

尝试将字符串写入文件时发生以下错误:

代码

logfile.write(cli_args.last_name)

输出

UnicodeEncodeError:“ascii”编解码器无法对位置 8-9 中的字符进行编码:序数不在范围内(128)

但这有效:

代码

print(cli_args.last_name)

输出

佩雷斯

为什么?

完整的上下文

我制作了一个脚本,它从 Linux CLI 接收数据,对其进行处理,最后使用提供的数据创建 Zendesk 票证。它是一种 CLI API,因为在我的脚本之前有一个更大的系统,它有一个带有表单的 Web 界面,用户可以在其中填写字段的值,然后替换为 CLI 脚本。例如:

myscript.py --first_name '_first_name_' --last_name '_last_name_'

该脚本工作没有问题,直到昨天更新网络。我认为他们改变了与字符集或编码相关的东西。

我通过打开一个文件并编写一些信息性消息来使用 F 字符串进行一些简单的日志记录,以防万一发生任何故障,因此我可以回去检查它发生的位置。此外,使用 argparse 模块读取 CLI 属性。例子:

logfile.write(f"\tChecking for opened tickets for user '{cli_args.first_name} {cli_args.last_name}'\n")

网站更新后,我收到如下错误:

UnicodeEncodeError:“ascii”编解码器无法对位置 8-9 中的字符进行编码:序数不在范围内(128)

进行一些故障排除后,我发现这是因为某些用户输入的名称带有重音符号,例如Carlos Pérez.

我需要脚本再次工作,并为这样的输入做准备,所以我通过检查 Web 控制台输入表单中的 HTTP 标头来寻找答案,发现它使用Content-Type: text/html; charset=UTF-8; 我的第一次尝试是对str传入的 CLI 参数进行编码utf-8并使用相同的编解码器再次对其进行解码,但没有成功。

在我第二次尝试时,我检查了 Python 文档str.encode()bytes.decode()。所以我尝试了这个:

logfile.write(
    "\tChecking for opened tickets for user "
    f"'{cli_args.first_name.encode(encoding='utf-8', errors='ignore').decode('utf-8')} "
    f"{cli_args.last_name.encode(encoding='utf-8', errors='ignore').decode('utf-8')}'"
)

它有效,但删除了重音标记的字母,因此Carlos PérezCarlos Prez这种情况下对我没有用,我需要完整的输入。

作为一个绝望的举动,我尝试打印我试图写入日志文件的相同 F 字符串,令我惊讶的是它起作用了。Carlos Pérez它在没有任何编码/解码过程的情况下打印到控制台。

打印是如何工作的?为什么尝试写入文件不起作用?但最重要的是如何写入与打印格式相同的文件?

编辑 1 @MarkTolonen

尝试了以下方法:

logfile = open("/usr/share/pandora_server/util/plugin/plugin_mcm/sandbox/755bug.txt", mode="a", encoding="utf8")
logfile.write(cli_args.body)
logfile.close()

输出:

回溯(最后一次调用):文件“/usr/share/pandora_server/util/plugin/plugin_mcm/sandbox/ticket_query_app.py”,第 414 行,在 main() 文件“/usr/share/pandora_server/util/plugin/ plugin_mcm/sandbox/ticket_query_app.py", line 81, in main logfile.write(cli_args.body) UnicodeEncodeError: 'utf-8' codec can't encode characters in position 8-9: surrogates not allowed

编辑 2

我设法得到导致问题的文本:

if __name__ == "__main__":
    string = (
        "Buenos d\udcc3\udcadas,\r\n\r\n"
        "Mediante  monitoreo autom\udcc3\udca1tico se ha detectado un evento fuera de lo normal:\r\n\r\n"
        "Descripci\udcc3\udcb3n del evento: _snmp_f13_\r\n"
        "Causas sugeridas del evento: _snmp_f14_\r\n"
        "Posible afectaci\udcc3\udcb3n del evento: _snmp_f15_\r\n"
        "Validaciones de bajo impacto: _snmp_f16_\r\n"
        "Fecha y hora del evento: 2021-07-14 17:47:51\r\n\r\n"
        "Saludos."
    )

    # Output: Text with the unicodes translated
    print(string)

    # Output: "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 8-9: surrogates not allowed"
    with open(file="test.log", mode="w", encoding="utf8") as logfile:
        logfile.write(string)

标签: pythonpython-3.xstringfilewrite

解决方案


答案是 的encoding参数open。观察:

Last login: Wed Jul 14 15:05:24 2021 from 50.126.68.34
[timrprobocom@jared-ingersoll ~]$ python3
Python 3.6.9 (default, Jan 26 2021, 15:33:00)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> f = open('x.txt','a')
>>> g = open('y.txt','a',encoding='utf-8')
>>> s = "spades \u2660 spades"
>>> f.write(s)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character '\u2660' in position 7: ordinal not in range(128)
>>> g.write(s)
15
>>>
[timrprobocom@jared-ingersoll ~]$ hexdump -C y.txt
00000000  73 70 61 64 65 73 20 e2  99 a0 20 73 70 61 64 65  |spades ... spade|
*
00000011

推荐阅读