python - 如何写入与打印格式相同的文件?
问题描述
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érez
在Carlos 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)
解决方案
答案是 的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
推荐阅读
- logging - Clojure - 如何暂时禁用日志记录?
- sql - 使用 crypt_gen_random 生成唯一的序列号
- python - python列表+空numpy数组=空numpy数组?
- google-apps-script - Google 脚本属性会更改类型吗?
- angular - 带有 switchMap 和 catchError 的 NgRx 效果 - 有人可以解释我的代码和“正确”代码之间的可观察工作流程的区别吗?
- java - Java 运行终端命令并发送输入
- http - 在 HTTP 标头中表示真值和假值的标准格式是什么?
- docker - 启动数据库后容器不启动
- gcc - 编译 xorg-server 时出现 libexa 错误
- angular - 如何从组件中的缓存服务中获取价值