首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何以与打印格式相同的格式写入文件?

如何以与打印格式相同的格式写入文件?
EN

Stack Overflow用户
提问于 2021-07-14 21:47:30
回答 2查看 212关注 0票数 0

TL;DR

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

代码

代码语言:javascript
复制
logfile.write(cli_args.last_name)

输出

UnicodeEncodeError:'ascii‘编解码器不能在8-9位置编码字符:序数不在范围内(128个)

但这样做是可行的:

代码

代码语言:javascript
复制
print(cli_args.last_name)

输出

佩雷斯

为什么?

全上下文

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

代码语言:javascript
复制
myscript.py --first_name '_first_name_' --last_name '_last_name_'

直到昨天,这个脚本才被更新。我想他们改变了一些与字符集或编码有关的东西。

我使用F-字符串进行一些简单的日志记录,方法是打开一个文件并编写一些信息信息,以防任何事情失败,所以我可以回去检查它发生在哪里。另外,CLI属性是使用are解析模块读取的。示例:

代码语言:javascript
复制
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控制台输入表单中的headers来寻找答案,并发现它使用了Content-Type: text/html; charset=UTF-8;我的第一次尝试是对传递给utf-8的CLI参数中的str进行编码,并使用相同的编解码器再次对其进行解码,但没有成功。

在第二次尝试中,我检查了Python str.encode()bytes.decode()。所以我试了一下:

代码语言:javascript
复制
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

试过以下几点:

代码语言:javascript
复制
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,主() "/usr/share/pandora_server/util/plugin/plugin_mcm/sandbox/ticket_query_app.py",行81,主logfile.write(cli_args.body) UnicodeEncodeError:'utf-8‘编解码器不能编码位置8-9的字符:不允许代理

编辑2

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

代码语言:javascript
复制
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)
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-07-15 02:45:17

看来上游的东西配置不当了。您的string似乎是由具有错误编码和errors='surrogateescape'错误处理的decode操作生成的。从显示的数据来看,似乎解码操作试图将UTF-8编码的文本解码为ASCII.

errors='surrogateescape'是编码在decode操作期间处理无效字节的一种方法。当转换为Unicode字符串时,错误处理程序将使用范围U+DC80..U+DCFF中的部分代理替换无效字节,并且可以通过使用encode和相同的编码执行encode来反转进程以获得原始字节字符串。

您的string中的部分代理与当给定的数据实际编码为UTF-8时decode(encoding='ascii', errors='surrogateescape')调用所产生的模式相匹配--代理项都在surrogateescape使用的范围内,它们对应的字节构成有效的UTF-8。在下面的代码中,我恢复原始字节,然后将它们正确解码为UTF-8。一旦Unicode字符串有效,就可以使用encoding='utf8'将其写入日志文件。

代码语言:javascript
复制
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."
)

fixed = string.encode('ascii',errors='surrogateescape').decode('utf8')
print(fixed)

with open(file="test.log", mode="w", encoding="utf8") as logfile:
    logfile.write(fixed)

您可以在佩普383中阅读更多关于代理转义的内容。

票数 1
EN

Stack Overflow用户

发布于 2021-07-14 22:10:00

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

代码语言:javascript
复制
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
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68385436

复制
相关文章

相似问题

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