命令行参数作为字节而不是python3中的字符串

Posted

技术标签:

【中文标题】命令行参数作为字节而不是python3中的字符串【英文标题】:Command-line arguments as bytes instead of strings in python3 【发布时间】:2011-04-03 05:42:21 【问题描述】:

我正在编写一个 python3 程序,它从命令行参数获取要处理的文件名。我对处理不同编码的正确方法感到困惑。

我认为我宁愿将文件名视为字节而不是字符串,因为这样可以避免使用不正确编码的危险。事实上,我的一些文件名使用了不正确的编码(当我的系统语言环境使用 utf-8 时为 latin1),但这并不妨碍像 ls 这样的工具工作。我希望我的工具也能适应这种情况。

我有两个问题:命令行参数以字符串形式提供给我(我使用 argparse),我想以字符串形式向用户报告错误。

我已经成功地调整了我的代码以使用二进制文件,并且我的工具可以处理名称在当前默认编码中无效的文件,只要它是通过文件系统递归,因为我很早就将参数转换为二进制文件,并在调用 fs 函数时使用二进制文件。但是,当我收到一个无效的文件名参数时,它会作为带有 \udce8 之类的奇怪字符的 unicode 字符串交给我。我不知道这些是什么,并且尝试对其进行编码总是失败,无论是使用 utf8 还是使用相应的(错误)编码(此处为 latin1)。

另一个问题是报告错误。我希望我的工具的用户能够解析我的标准输出(因此想要保留文件名),但是当报告标准错误时,我宁愿将其编码为 utf-8,用适当的“无效/问号”字符替换无效序列。

所以,

1) 有更好的、完全不同的方法吗? (是的,已计划修复文件名,但我仍然希望我的工具功能强大)

2) 我如何获取原始二进制形式的命令行参数(未为我预解码),知道对于无效序列重新编码已解码的参数将失败,并且

3) 我如何告诉 utf-8 编解码器用一些无效标记替换无效的、不可解码的序列而不是死在我身上?

【问题讨论】:

【参考方案1】:

当我收到文件名参数时 这是无效的,但是,它是 作为一个unicode字符串交给我 像 \udce8 这样的奇怪字符。

这些是代理字符。低8位是原来的无效字节。

见PEP 383: Non-decodable Bytes in System Character Interfaces。

【讨论】:

好的,这就是第 2 点。所以正确的做法是在我只对 CLI 参数进行编码时添加“surrogateescape”?还是使用代理工具将所有内容作为字符串处理?其他点呢? 至少我最关心的问题得到了解决,所以回答接受了! Python 3.1(但不是 3.0)应该自动处理 surrogateescape。只需将文件名视为字符串。【参考方案2】:

不要违背常规:文件名是字符串,而不是字节。

当您应该使用string 时,您不应该使用bytesbytes 是一个整数元组。 string 是一个字符元组。它们是不同的概念。你所做的就像在应该使用布尔值时使用整数。

(旁白:Python 以 Unicode 将所有字符串存储在内存中;所有字符串的存储方式相同。编码指定 Python 如何将文件中的字节转换为这种内存格式。)

您的操作系统将文件名存储为特定编码下的字符串。我很惊讶您说某些文件名具有不同的编码;据我所知,文件名编码是系统范围的。比如open之类的函数默认使用默认的系统文件名编码。

【讨论】:

我希望我的操作系统将文件名视为字符串,但有很多事情表明情况并非如此。我尝试使用不同的语言环境设置运行 ls,它仍然给我相同的确切字节序列。如果语言环境与文件系统编码不同,则不会执行转码。 我会在任何地方都使用字符串(这就是我最初所做的)但它不起作用,现在我认为原因是我正在使用的库之一(pyxattr)处理代理人失败。

以上是关于命令行参数作为字节而不是python3中的字符串的主要内容,如果未能解决你的问题,请参考以下文章

main中的argv和argc

您如何将 zip 文件中的文件作为文本而不是字节读取?

Python3 - 读写字节数据

读取在 SSH 服务器上执行的命令的输出,使用 Paramiko 作为字符串,而不是字节

TypeError: int() 参数必须是字符串、类似字节的对象或数字,而不是使用 Python 3.7 时的“NoneType”

安装了python2跟python3命令行怎么区分