我正在尝试从 python 运行 Powershell 脚本并打印输出,但输出包含特殊字符“é”。
process = subprocess.Popen(\[r'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', 'echo é'\], stdout=subprocess.PIPE)
print(process.stdout.read().decode('cp1252'))
返回“,”
process = subprocess.run(r'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe echo é', stdout=subprocess.PIPE)
print(process.stdout.decode('cp1252'))
返回“,”
print(subprocess.check_output(r'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe echo é').decode('cp1252'))
返回“,”
除了子进程之外还有其他方法吗,或者我应该使用不同的编码?
UTF-8 对 é 给出错误,但对 ® 返回“r”。 UTF-16-le 给出错误“UnicodeDecodeError:'utf-16-le'编解码器无法解码位置 2 中的字节 0x0a:截断的数据”。
PowerShell CLI 使用活动控制台窗口的代码页,如 chcp
的输出所示,默认情况下是旧系统区域设置的OEM 代码页,例如(用Python术语表达)
cp437
.相比之下,
cp1252
是一个ANSI 代码页。 一种选择是简单地
通过 WinAPI 查询控制台窗口的活动(输出)代码页并使用返回的编码:
import subprocess
from ctypes import windll
# Get the console's (output) code page, which the PowerShell CLI
# uses to encode its output.
cp = windll.kernel32.GetConsoleOutputCP()
process = subprocess.Popen(r'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe echo é', stdout=subprocess.PIPE)
# Decode based on the active code page.
print(process.stdout.read().decode('cp' + str(cp)))
但是,请注意 OEM 代码页限制为 256 个字符;而 é
可以 表示为 CP437,例如其他 Unicode 字符,例如
€
,则不能。因此
robust选项是(暂时)将控制台输出代码页设置为65001
,即UTF-8:
import subprocess
from ctypes import windll
# Save the current console output code page and switch to 65001 (UTF-8)
previousCp = windll.kernel32.GetConsoleOutputCP()
windll.kernel32.SetConsoleOutputCP(65001)
process = subprocess.Popen(r'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe echo é€', stdout=subprocess.PIPE)
# Decode as UTF-8
print(process.stdout.read().decode('utf8'))
# Restore the previous output console code page.
windll.kernel32.SetConsoleOutputCP(previousCp)
注:
itself 用于其输出流的字符编码无关。
Python UTF-8 模式,使其将输入解码为 UTF-8 并生成 UTF-8 输出,请传递命令行选项 -X utf8
(v3.7+) 或在调用 (v3+) 之前定义环境变量
PYTHONUTF8
,其值为
1
。