Note:
-
在 Windows 上,关于渲染统一码字符,它主要是的选择font / 控制台(终端)应用这很重要。
- 如今,使用Windows 终端 https://github.com/microsoft/terminal自 Windows 10 起通过 Microsoft Store 分发和更新,是一个很好的替代品传统控制台主机(控制台窗口由
conhost.exe
),提供卓越的 Unicode 字符支持。在 Windows 11 22H2 中,Windows Terminal 甚至成为了default控制台(终端) https://devblogs.microsoft.com/commandline/windows-terminal-is-now-the-default-in-windows-11/.
-
关于以编程方式处理 Unicode人物当与外部程序, $OutputEncoding
, [Console]::InputEncoding
and [Console]::OutputEncoding
也很重要 - 见下文。
The PowerShell(核心)7+ https://github.com/PowerShell/PowerShell/blob/master/README.md观点(参见下一节Windows PowerShell),与性格无关渲染问题(也将在下一节中介绍),就沟通而言与外部程序:
-
On Unix类平台、PowerShell Core使用UTF-8 默认情况下.
-
On Windows, 它是legacy 系统区域设置,通过其OEM 代码页,决定默认编码但在所有控制台中,包括 Windows PowerShell 和 PowerShell Core 控制台窗口最新版本的 Windows 10 现在允许将系统区域设置设置为代码页65001
(UTF-8);请注意,截至撰写本文时,该功能仍处于测试阶段,并且使用它已经影响深远 - see 这个答案 https://stackoverflow.com/a/57134096/45375.
制作你的Windows PowerShell控制台窗口支持 Unicode (UTF-8):
Windows PowerShell 中的以下魔法咒语可以实现此目的(如上所述,这隐含地施行chcp 65001
):
$OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding =
New-Object System.Text.UTF8Encoding
To persist这些设置,即让您未来的交互式 PowerShell 会话默认支持 UTF-8,将上面的命令添加到您的$PROFILE
file.
注意:最新版本的 Windows 10 现在允许设置系统区域设置到代码页65001 (UTF-8) https://stackoverflow.com/a/57134096/45375(截至 Window 10 版本 1903,该功能仍处于测试阶段),这使得all控制台窗口默认为 UTF-8,包括 Windows PowerShell。
如果您确实使用该功能,请设置[Console]::InputEncoding
/ [Console]::OutputEncoding
那么不再是绝对必要的,但你仍然需要设置$OutputEncoding
(这在 PowerShell 中不是必需的Core, where $OutputEncoding
已默认为 UTF-8)。
重要的:
-
These 设置假定您与之通信的任何外部实用程序都期望 UTF-8 编码输入并生成 UTF-8 输出.
- 例如,用 Node.js 编写的 CLI 就满足该标准。
- Python 脚本 - 如果编写时考虑到 UTF-8 支持 - 也可以处理 UTF-8(请参阅这个答案 https://stackoverflow.com/a/67778646/45375).
-
相比之下,这些设置可以break(较旧的)只需要单字节编码的实用程序正如系统的旧版 OEM 代码页所暗示的那样。
- 直到 Windows 8.1,这甚至包括标准 Windows 实用程序,例如
find.exe
and findstr.exe
,这些问题已在 Windows 10 中修复。
- 请参阅本文底部,了解如何通过切换到 UTF-8 来绕过此问题暂时的,按需的用于调用给定的实用程序。
-
这些设置适用于仅外部程序并且与编码无关PowerShell 的 cmdlet在输出上使用:
- See 这个答案 https://stackoverflow.com/a/40098904/45375PowerShell cmdlet 使用的默认字符编码;简而言之:如果您想要 cmdletWindows PowerShell默认为 UTF-8(其中PowerShell [核心] v6+无论如何),添加
$PSDefaultParameterValues['*:Encoding'] = 'utf8'
给你的$PROFILE
,但请注意,这将影响对 cmdlet 的所有调用-Encoding
会话中的参数,除非明确使用该参数;还请注意,在Windows PowerShell你总是会得到 UTF-8 文件with BOM;相反,在PowerShell [核心] v6+,默认为 BOM-lessUTF-8(都在没有-Encoding
与-Encoding utf8
,你必须使用'utf8BOM'
.
可选背景信息
Tip of the hat to eryksun https://stackoverflow.com/users/205580/eryksun for all his input.
-
当 TrueType 字体处于活动状态时, 控制台窗口buffer正确保留(非 ASCII)Unicode 字符。即使他们不这样做render正确地;也就是说,即使他们可能appear一般为?
,以表明当前字体不支持,您可以复制粘贴正如 eryksun 指出的那样,这些字符可以在其他地方使用,而不会丢失信息。
-
PowerShell能够输出Unicode字符到控制台即使没有切换到代码页65001
first.
然而,这本身确实not保证其他程序可以正确处理此类输出 - 见下文。
-
到那个时刻与…沟通外部程序 via stdout (piping), Powershell 使用中指定的字符编码$OutputEncoding
偏好变量, which Windows PowerShell 中默认为 ASCII(!),这意味着任何非 ASCII 字符都会音译为literal ?
字符,导致信息丢失。 (相比之下,值得称赞的是,PowerShellCore(v6+) 现在一致使用(无 BOM)UTF-8 作为默认编码。)
- 然而相比之下,传递非 ASCII论点(而不是 stdout(管道)输出)外部程序似乎需要no特殊配置(我不清楚为什么会这样);例如,以下 Node.js 命令正确返回
€: 1
即使使用默认配置:
node -pe "process.argv[1] + ': ' + process.argv[1].length" €
-
[Console]::OutputEncoding
:
- 控制当控制台将程序输出转换为控制台显示字符时采用的字符编码。
- also tells 电源外壳何时采用什么编码捕获输出来自外部程序.
结果是,如果你需要捕获输出从生成 UTF-8 的程序中,您需要设置[Console]::OutputEncoding
也为 UTF-8;环境$OutputEncoding
仅涵盖input(对于外部程序)方面。
-
[Console]::InputEncoding
sets the encoding for keyboard input into a console[2] and also determines how PowerShell's CLI https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_pwsh interprets data it receives via stdin (standard input).
-
如果将控制台切换为 UTF-8整个会议不是一个选择,你可以这样做暂时,对于给定的呼叫:
# Save the current settings and temporarily switch to UTF-8.
$oldOutputEncoding = $OutputEncoding; $oldConsoleEncoding = [Console]::OutputEncoding
$OutputEncoding = [Console]::OutputEncoding = New-Object System.Text.Utf8Encoding
# Call the UTF-8 program, using Node.js as an example.
# This should echo '€' (`U+20AC`) as-is and report the length as *1*.
$captured = '€' | node -pe "require('fs').readFileSync(0).toString().trim()"
$captured; $captured.Length
# Restore the previous settings.
$OutputEncoding = $oldOutputEncoding; [Console]::OutputEncoding = $oldConsoleEncoding
-
旧版本 Windows(W10 之前)上的问题:
- 一个活跃的
chcp
的价值65001
在旧版本的 Windows 中,破坏某些外部程序甚至批处理文件的控制台输出最终可能是由于WriteFile()
Windows API 函数(标准 C 库也使用),错误地报告了数量人物而不是bytes带代码页65001
实际上,正如所讨论的这篇博文 http://blogs.msdn.com/b/michkap/archive/2011/03/09/10138478.aspx.
-
据评论称,由此产生的症状bobince https://stackoverflow.com/users/18936/bobince on 这个答案 https://stackoverflow.com/a/388500/45375从 2008 年开始,是:“我的理解是,返回字节数的调用(例如 fread/fwrite/等)实际上返回字符数。这会导致各种各样的症状,例如输入不完整 -读取、挂起、批处理文件损坏等等。”
本地 Windows 控制台(终端)的高级替代品,conhost.exe
eryksun 建议两种本机 Windows 控制台窗口的替代品 (conhost.exe
),哪个提供商更好更快的 Unicode 字符渲染,由于使用现代 GPU 加速的 DirectWrite/DirectX API,而不是“无法处理复杂脚本、非 BMP 字符或自动后备字体的旧 GDI 实现”。
-
微软自己的,开源的Windows 终端 https://github.com/microsoft/terminal,自 Windows 10 起通过 Microsoft Store 分发和更新 - 请参阅here https://devblogs.microsoft.com/commandline/introducing-windows-terminal/进行介绍。
-
历史悠久的第三方替代品ConEmu https://conemu.github.io/,它的优点是也可以在较旧的 Windows 版本上运行。
[1] Note that running chcp 65001
from inside a PowerShell session is not effective, because .NET caches the console's output encoding on startup and is unaware of later changes made with chcp
(only changes made directly via [console]::OutputEncoding]
are picked up).
[2] I am unclear on how that manifests in practice; do tell us, if you know.