我一直在命令提示符和Windows Powershell中强制使用chcp 65001,但是从SO和其他几个社区的问答环节来看,这似乎是一种危险且低效的解决方案。 Microsoft是否提供了chcp 65001的改进/完整替代方案,可以在不手动更改注册表的情况下将其永久保存? 如果没有,将来是否有公开宣布的时间表或议程来支持Windows CLI中的UTF-8?
我个人一直在使用chcp 949来支持韩文字符,但是反斜杠 \ 的显示很奇怪,并且在某些应用程序(例如Neovim)中显示不正确/无法理解,并且不能通过以下方式支持不支持韩文的字符 949最近似乎变得越来越成问题。
-
有趣,谢谢! (尽管投票最多,但警告评论已有8年历史了,我怀疑它们是否仍然适用。)
-
@Tomalak,在Windows 8之前,向控制台的WriteFile返回已写入的已解码UTF-16代码点的数量,这可能会导致缓冲写入器出现问题,因为它们期望这应该是已写入的UTF-8字节的数量。是。对于控制台中的ReadFile,即使在Windows 10中,如果输入代码页设置为UTF-8,由于控制台主机conhost.exe中的错误假设,您也将被限制为7位ASCII。在Windows 10中,它在缓冲区中以null(" \ 0")的形式返回非ASCII字符。在较旧的版本中,读取成功后读取0个字节,看起来像EOF。
-
现代Windows程序应使用Unicode控制台功能WriteConsoleW和ReadConsoleW。然后唯一的限制是Unicode控制台的固有限制,即仅限于基本的多语言平面;不支持复杂的脚本和组合代码;如果所选字体没有字符字形,则不支持字体回退。最终,Microsoft可能会更新经典的控制台主机,以通过切换到基于DirectWrite的实现来消除这些限制,但是目前,他们(以及开源贡献者)的工作重点都放在新的Windows终端上。
注意:
此答案显示了如何将Windows控制台中的字符编码切换为UTF-8(代码页65001),以便与外部(控制台)通信时,诸如cmd.exe和PowerShell的外壳程序可以正确地编码和解码字符(文本)。 PowerShell和cmd.exe中的程序也用于文件I / O.1
相比之下,如果您关注控制台窗口中Unicode字符呈现限制的单独方面,请参阅此答案的中下部,在此还将讨论其他控制台(终端)应用程序。
Does Microsoft provide an improved / complete alternative to chcp 65001 that can be saved permanently without manual alteration of the Registry?
Ok.
从(至少)Windows 10版本1903起,您可以选择将系统区域设置(非Unicode程序的语言)设置为UTF-8,但在撰写本文时此功能处于beta版本。
要激活它:
运行intl.cpl(在"控制面板"中打开区域设置)
请按照以下屏幕快照中的说明进行操作。
这将使以后的所有控制台窗口默认为UTF-8(chcp 65001)。
注意事项:
如果您使用的是Windows PowerShell,这还将使Get-Content和Set-Content(可能还有Windows PowerShell默认的其他上下文,因此系统的活动ANSI代码页)默认为UTF-8(PowerShell Core(v6 +)始终会这样做) )。这意味着,在没有-Encoding参数的情况下,然后会误读经过ANSI编码的无BOM文件(这在历史上很常见),并且使用Set-Content创建的文件将为UTF-8,而不是ANSI-编码。
至少在PowerShell 7.0之前,基础.NET版本(.NET Core 3.1)中的错误会导致PowerShell中的后续错误:通过stdin意外地将UTF-8 BOM传递给外部进程的数据(无论您使用什么)将$OutputEncoding设置为),这会明显破坏Start-Job-请参见此GitHub问题。
并非所有字体都使用Unicode,因此请选择TT(TrueType)字体,但即使它们通常仅支持所有字符的一个子集,因此您可能必须尝试使用??特定字体以查看是否关心的所有字符都得到表示-请参阅此答案有关详细信息,还讨论了具有更好的Unicode渲染支持的替代控制台(终端)应用程序。
正如eryksun指出的那样,不"讲" UTF-8的旧式控制台应用程序将仅限于纯ASCII输入,并且在尝试输出(7位)ASCII范围以外的字符时将产生错误的输出。 (在过时的Windows 7及更低版本中,程序甚至可能会崩溃)。
如果运行旧版控制台应用程序对您来说很重要,请参阅注释中eryksun的建议。
但是,对于Windows PowerShell,这还不够:
您还必须另外将$OutputEncoding首选项变量设置为UTF-8:$OutputEncoding = System.Text.UTF8Encoding;将命令添加到$PROFILE(仅当前用户)或$PROFILE.AllUsersCurrentHost(所有用户)文件中是最简单的。
幸运的是,在PowerShell Core中不再需要此功能,PowerShell Core在内部始终默认为无BOM的UTF-8。
如果在您的环境中不能将系统语言环境设置为UTF-8,则使用启动命令代替:
注意:上述注意事项在这里同样适用。如果运行旧版控制台应用程序对您来说很重要,请参阅注释中eryksun的建议。
对于PowerShell(两个版本),将以下行添加到$PROFILE(仅当前用户)或$PROFILE.AllUsersCurrentHost(所有用户)文件中,该文件等效于chcp 65001,并补充设置首选项变量$OutputEncoding以指示PowerShell通过UTF-8中的管道将数据发送到外部程序:
请注意,从PowerShell会话内部运行chcp 65001无效,因为.NET在启动时会缓存控制台的输出编码,并且不知道以后对chcp所做的更改;此外,如上所述,Windows PowerShell要求设置$OutputEncoding-有关详细信息,请参见此答案。
1
| $OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding |
例如,以下是一种通过编程将这行添加到$PROFILE的快捷方法:
1
| '$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding' + [Environment]::Newline + (Get-Content -Raw $PROFILE) | Set-Content -Encoding utf8 $PROFILE |
对于cmd.exe,通过注册表 HKEY_CURRENT_USER\\Software\\Microsoft\\Command Processor(仅当前用户)或HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Command Processor(所有用户)的值AutoRun定义一个自动运行命令:
例如,您可以使用PowerShell为您创建此值:
1 2 3
| # Auto-execute `chcp 65001` whenever the current user opens a `cmd.exe` console
# window (including when running a batch file):
Set-ItemProperty 'HKCU:\\Software\\Microsoft\\Command Processor' AutoRun 'chcp 65001 >NUL' |
可选阅读:为什么Windows PowerShell ISE是一个较差的选择:
尽管ISE确实比控制台具有更好的Unicode渲染支持,但通常是一个差的选择:
首先,ISE已过时:它不支持PowerShell Core,将来所有的开发都会进行下去,而且它也不是跨平台的,这与两个PowerShell版本的新的首要IDE(Visual Studio Code)不同默认情况下,PowerShell Core的UTF-8可以配置为Windows PowerShell。
ISE通常是一个用于开发脚本的环境,而不是用于在生产环境中运行它们的环境(如果您还为其他人编写脚本,则应假定它们将在控制台中运行)。值得注意的是,在运行脚本方面,ISE的行为在所有方面都不尽相同。
正如eryksun所指出的,ISE不支持运行交互式外部控制台程序,即需要用户输入的程序:
The problem is that it hides the console and redirects the process output (but not input) to a pipe. Most console applications switch to full buffering when a file is a pipe. Also, interactive applications require reading from stdin, which isn't possible from a hidden console window. (It can be unhidden via ShowWindow, but a separate window for input is clunky.)
Ok.
如果您愿意遵守该限制,那么将活动代码页切换为65001(UTF-8)以便与外部程序进行正确的通信需要一种尴尬的解决方法:
您必须首先通过运行内置控制台中的任何外部程序(例如chcp)来强制创建隐藏的控制台窗口-您会看到控制台窗口短暂闪烁。
只有这样,您才能将[console]::OutputEncoding(和$OutputEncoding)设置为UTF-8,如上所示(如果尚未创建隐藏的控制台,则会得到一个handle is invalid error)。
1在PowerShell中,如果您从不调用外部程序,则无需担心系统区域设置(活动代码页):PowerShell本地命令和.NET调用始终通过UTF-16字符串(本地.NET字符串)和文件进行通信I / O应用独立于系统区域设置的默认编码。同样,由于Windows API函数的Unicode版本用于向控制台打印和从控制台读取,因此非ASCII字符始终可以正确打印(在控制台的呈现限制内)。
相比之下,在cmd.exe中,系统区域设置对于文件I / O也很重要(特别是包括批处理文件源代码采用的编码),而不仅仅是与外部程序进行通信,例如在读取< x6>循环。
好。
-
将控制台输入代码页设置为UTF-8,可以将通过ReadFile读取的旧程序限制为7位ASCII输入。 (输出将在Windows 8之前中断,但Windows 7仍将退出EOL。)如果将系统区域设置设置为UTF-8,则建议将" HKEY_CURRENT_USER \ Console \%SystemRoot%_system32_cmd.exe"设置为" CodePage"值(以及其他感兴趣的窗口标题)添加到旧版OEM代码页中,以便旧版非Unicode控制台应用程序将继续在您的语言环境中正常运行。请勿在批处理脚本中临时使用chcp.com 65001,例如对于for f循环。
-
PowerShell和CMD使用控制台Unicode API,因此,控制台代码页的这些设置仅与运行外部控制台应用程序时shell设置的输入和输出控制台代码页有关,而与cmdlet等外壳程序内部无关, Shell处理文件和管道中的文本时使用输入和输出编码设置的程度。我不确定与此相关如何在PowerShell中使用这些设置,但是CMD在解码批处理脚本并从for f循环中读取程序的管道输出时会使用控制台输出代码页。
-
谢谢@eryksun,像往常一样提供良好的背景信息。但是,如果您知道局限性并(主要)运行支持UTF-8的程序,则全局设置chcp.com 65001(或等效设置)是一个可行的选择,但是我为答案添加了警告,指出您的评论。
-
@eryksun:对于PowerShell:外部程序的stdout输出根据[console]::OutputEncoding进行解码,并且通过管道发送到外部程序的文本基于首选项变量$OutputEncoding进行编码。重新归档:Windows PowerShell:除非存在BOM,否则读取默认为ANSI;否则,默认为ANSI。将默认值写入具有> / Out-File的UTF-16LE和具有Set-Content的ANSI;幸运的是,PowerShell Core_now在所有这些情况下始终使用无BOM的UTF-8。
-
更改系统区域设置后,VS出现了令人不快的惊喜(我的版本是16.7.2):通过将UTF-8字符替换为某些Unicode占位符,所有包含UTF-8的文件都被强制破坏。每个打开的文件之前都有红色的大错误消息
-
@dyomas,将系统区域设置更改为UTF-8(代码页65001)后发生了吗?您的症状听起来像文件是ANSI编码的,然后开关使Visual Studio将其解释为UTF-8编码。
-
没有!这是完全用Unicode保存的(没有签名的UTF-8)-代码页65001文件包含许多俄语注释和一些UTF-8特定符号,例如箭头(→,←),数学运算符≡,≥,≤和等等...
-
@dyomas,除非您只是想警告其他人,否则我建议您提出一个新问题以深入了解此问题。
-
我向MS报告了问题,收到确认。等候…
您可以将命令chcp 65001放在Powershell配置文件中,当您打开Powershell时它将自动运行它。但是,这对于cmd.exe不会执行任何操作。
Microsoft当前正在开发一种改进的终端,该终端将具有完全的Unicode支持。它是开源的,如果您使用的是Windows 10版本1903或更高版本,则可以下载预览版本。
或者,您可以使用第三方终端仿真器,例如Terminus。
-
不幸的是,在PowerShell会话内部运行chcp 65001无效,因为.NET在启动时会缓存控制台输出的编码;因此,在Windows上运行chcp 65001无效。此外,Windows PowerShell(但不是PowerShell Core)需要设置$OutputEncoding。
Powershell ISE可以完美显示韩语。这是可以使用utf8编码的示例文本文件:
1 2 3 4 5
| PS C:\\Users\\js> cat .\\korean.txt
The Korean language (South Korean: ???/韓國語 Hangugeo; North
Korean: ???/朝鮮? Chos?nmal) is an East Asian language
spoken by about 77 million people.[3] |
由于ISE随Windows 10的每个版本一起提供,因此我认为它已经过时了。我不同意删除原始答案的人。
ISE有一些限制,但是可以使用外部命令来完成某些脚本编制:
1 2
| echo 'list volume' | diskpart # as admin
cmd /c echo hi |
编辑:
如果您使用的是Windows 10 1903,则可以从Microsoft商店https://devblogs.microsoft.com/commandline/introducing-windows-terminal/下载Windows Terminal,并且韩文文本可以在其中使用。 Powershell 5将需要文本格式为带有bom的UTF8或UTF16。
编辑2:
似乎理想的是Windows终端+ powershell 7或vscode + powershell 7,用于粘贴字符和输出。
编辑3:
即使在EDIT2情况下,也无法粘贴某些Unicode字符,例如?(U + 21C6)或Unicode空间。只有Osx中的PS7可以工作。
-
ISE当然是一个功能强大的工具,但是仅凭ISE无法完成某些操作。例如,我将Neovim与PowerShell终端一起使用,这不是ISE的可用选项。
-
ISE是用于运行PowerShell脚本的环境。它不支持交互式控制台应用程序(例如diskpart.exe,python.exe shell)。问题在于它隐藏了控制台,并将流程输出(而不是输入)重定向到管道。当文件是管道时,大多数控制台应用程序会切换到完全缓冲。另外,交互式应用程序需要从stdin中读取,这是不可能从隐藏的控制台窗口中读取的。 (可以通过ShowWindow取消隐藏,但是单独的输入窗口很笨拙。)
-
js2010:一位主持人删除了您的答案,我猜想为什么它可能被标记为低质量答案,因为它没有提供任何解释。病态将重新发布已删除的注释以及您的答案,但要添加到@eryksuns点,以他们对我的答案的注释为基础:如果仅将活动限制在PowerShell本机命令中,则无需担心代码页-都不用担心在控制台或ISE中。当您与外部(控制台)应用程序对话时,代码页很重要,因此ISE比控制台更差。
-
过时的PowerShell ISE使您两全其美:它使用活动的ANSI代码页,因此它既不能与使用OEM代码页的旧式控制台应用程序一起使用,也不能与UTF-8程序一起使用。而且,表面上看,甚至无法更改默认编码(chcp调用被静默忽略,并且分配给[console]::OutputEncoding会产生"句柄无效"错误)。要获得类似于IDE的体验,默认情况下PowerShel Core会讲UTF-8,并且可以将其配置为Windows PowerShell,那么请使用Visual Studio Code。
-
@ mklement0,如果仅与使用PowerShell和非交互式控制台程序有关,那么PowerShell ISE确实比控制台提供更好的Unicode支持,包括对非BMP字符(例如,大多数表情符号),复杂脚本(例如,使用零宽度连接符)和字体后备广告。对我而言,在Windows 10中,chcp.com在ISE中可以正常工作。它设置控制台应用程序默认继承的隐藏控制台的输入和输出代码页。
-
某些控制台应用程序在写入标准输出时,即使其是管道(如PowerShell ISE用于标准输出),也可能会使用控制台输入/输出代码页。在从非交互式命令获取输出的特定情况下,值得运行chcp.com 65001。如果stdout是管道,则其他控制台应用程序将忽略控制台。例如,在这种情况下,Python将始终使用系统ANSI代码页,除非我们通过PYTHONIOENCODING环境变量或通过PYTHONUTF8环境变量或< x6>命令行选项。
-
@eryksun:很高兴知道ISE具有更好的Unicode渲染支持,但这是有争议的,因为它既不能正确地渲染也不能正确地捕获来自外部程序的UTF-8输出,并且chcp不能帮助您:重要的是正确的PowerShell行为是[console]::OutputEncoding与外部程序的输出编码匹配,并且由于[console]::OutputEncoding在启动时缓存该编码(活动代码页),并且仅通过该属性识别以后的更改,因此在会话中运行chcp无效的。
-
@eryksun:现在我们知道可以进行真正的基于PowerShell conhost.exe的会话来正确地重定向/捕获来自外部程序的UTF-8输出(通过将[console]::OutputEncoding设置为UTF-8,如我的回答所述(在ISE中失败)),您会建议使用哪种基于控制台的替代方法以获得更好的渲染效果?您曾经提到ConEmu;新的Windows Terminal是否可以与ISE渲染功能相提并论?简而言之,是什么使ISE更好地呈现Unicode,并且Windows终端会采用相同的技术?
-
@ mklement0,PowerShell将自己作为中间人插入到管道和文件的重定向中,因此它用于解码程序输出的编码非常重要。但这不是更改OutputEncoding变量的问题吗?如果它是[console]::OutputEncoding的函数,我会觉得很奇怪。无论如何,首先尝试设置后者将失败,因为powershell_ise.exe最初没有控制台。它调用AllocConsole获取控制台,并在运行外部控制台应用程序之前隐藏窗口。之后,我们可以设置[console]::OutputEncoding。
-
@ mklement0,ConEmu或新的Windows Terminal都是不错的选择。在Windows 10中,我非常确定两者都可以利用新的伪控制台功能,但是ConEmu也可以在旧版Windows中使用。 conhost.exe与现代程序之间在Unicode处理方面的差异是因为conhost.exe基于经典的Windows GDI API,而较新的程序则使用DirectWrite API。
-
@eryksun:不,$OutputEncoding-也许令人惊讶-仅适用于发送到外部程序的数据;从外部程序的[stdout流]解码的数据始终基于[console]::OutputEncoding进行解释。感谢您提供有关使用哪种控制台的提示。好的一点是,在已分配隐藏控制台之后,可以设置[console]::OutputEncoding;但是,将这种解决方法称为尴尬将轻描淡写。在引起您注意的同时,请允许我切线:[console]::InputEncoding何时起作用我从未理解。