python - UTF-16/UTF-32 中的 Python 脚本文件:如何解决 BOM 和 PEP 263 的冲突?
问题描述
由于最近发现的 Unicode特洛伊木马源攻击(也在PEP 672中描述),我更深入地研究了 Python 脚本的 Unicode/字符编码行为。在 Python 2 中,必须使用PEP 263中定义的特定编码行启用 Unicode 编码,并且从 Python 3 开始,UTF-8 被设置为 Python 文件 ( PEP 3120 ) 的默认编码。
为了检测(所有)可能的木马源攻击,我想以 UTF-16 和 UTF-32 创建示例 python 脚本,作为自定义 linter 的测试文件。
现在PEP 263定义第一行(如果第一行是第二行,则为第二行#!/usr/bin/python
)不应包含任何非 ASCII 字符。相反,它首先需要一条特殊线路# -*- coding: <encoding name> -*-
。
这与定义 UTF-16 和 UTF-32 应包含 UTF-16 和 UTF-32 的 BOM 标记的 Unicode 标准(参见常见问题解答和SO 问题)相冲突。
现在,如果我创建一个带有 BOM 标记的 UTF-16(或 UTF-32)文件,Python 会抱怨:
SyntaxError: Non-UTF-8 code starting with '\xff' in file test_utf_16.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
另一方面,如果我省略了 BOM 标记, Gitlab 和 Gitlab 都vim
不会PyCharm
正确显示代码(如果我不手动更改编码):
更荒谬的是,如果我使用 UTF-16 或 UTF-32 对文件进行编码,Python (3.10) 不会抱怨,但也不会执行任何打印命令(即使 print 仅包含 ASCII)。
长话短说:
如何以 UTF-16 或 UTF-32 创建有效且工作的 Python 3 脚本文件,可以使用 vim 或 PyCharm(开箱即用)进行编辑?
更新:我还发现tokenize.detect_encoding
即使字符串在文件中,实现 PEP 263 也无法确定正确的编码。因为在 UTF-16/UTF-32 中,第一行不再匹配 ASCII 正则表达式。
因此,似乎不太可能生成以 UTF-16 或 UTF-32 编码的有效 python 脚本。或者是吗?
附录
用于创建测试文件的 Python 代码
# create_examples.py
from pathlib import Path
base_path = Path(__file__).parent.absolute()
def write_encoding(enc: str, strip_endian: bool = False):
encoding = enc.lower()
if encoding.endswith('be') or encoding.endswith('le'):
# As defined in unicode, if the le or the be is given, a BOM is not written
bom_used = False
if strip_endian:
enc = enc[:-3]
else:
bom_used = True
suffix = enc
if bom_used:
suffix += "_bom"
name = f"test_{encoding}_{suffix}.py"
content = f"# vim: set fileencoding={enc} :\n"
content += f"print(\"{name}\")\n"
content += 's = "x" * 100 # "x" is assigned'
content += "\n"
path = base_path / name
path.write_bytes(content.encode(encoding))
write_encoding('utf_8')
write_encoding('utf_16')
write_encoding('utf_16_be', False)
write_encoding('utf_16_be', True)
write_encoding('utf_16_le', False)
write_encoding('utf_16_le', True)
write_encoding('utf_32')
write_encoding('utf_32_be', False)
write_encoding('utf_32_be', True)
write_encoding('utf_32_le', False)
write_encoding('utf_32_le', True)
执行所有测试文件
for i in $(ls test_*); do python $i; done
解决方案
推荐阅读
- python - AWS CodeDeploy 失败,因为找不到 python3 命令
- gradle - 获得基本但详细的 Gradle 测试报告的最简单方法
- web - 购买域名并将其关联到我的电脑
- r - R 树 - 在树状图上显示频率
- python - 构建一个函数,该函数采用 2d 数组并在 python 中打印平均值
- asp.net-core - 在 Web Api 中将中介者模式与服务和存储库一起使用
- css - 使用 flexbox 时如何让图像保留在特定行上?
- r - ggplot 强大的集群 SE
- elasticsearch - 将数组与 ELASTICSEARCH 中的数组匹配
- git - 如何在此工作流程中保持服务器分支更新?