使用 UTF-8 编码的 Powershell 字符串变量

标签 powershell character-encoding windows-10 youtube-dl

我查了很多与此相关的问题,但找不到能解决我问题的东西。基本上,我想将一个 UTF-8 编码的字符串存储在一个变量中,然后将该字符串用作文件名。

例如,我正在尝试下载 YouTube 视频。如果我们打印视频标题,就会出现非英语字符(ytd 这里是 youtube-dl ):

./ytd https://www.youtube.com/watch?v=GWYndKw_zbw -e

输出:[LEEPLAY] 시티팝 입문 City Pop MIX(播放列表)

但是如果我将它存储在一个变量中并打印它,韩文字符将被忽略:

$vtitle= ./ytd https://www.youtube.com/watch?v=GWYndKw_zbw -e

$vtitle

输出:[LEEPLAY] City Pop MIX(播放列表)

最佳答案

有关 PowerShell 如何与外部程序交互的全面概述,包括向它们发送数据,请参阅 this answer .

当 PowerShell 解释来自外部程序的输出(例如您的情况下的 ytd)时,它假定输出使用反射(reflect)在 中的字符编码[控制台]::OutputEncoding.

注意:

  • 解释 是指 PowerShell 捕获(例如,$output = ...)、中继(例如,... | Select-String ...),或重定向(例如,...> output.txt >) 外部程序的输出。

  • 相比之下,直接打印到显示器可能不会受到影响,因为此时不涉及 PowerShell,并且某些 CLI 在其标准输出未重定向为直接打印时会调整其行为到具有完整 Unicode 支持的控制台(这解释了为什么当 ytd 的输出直接打印到它时字符在您的控制台中看起来像预期的那样)。

如果 [Console]::OutputEncoding 报告的编码与手头的外部程序使用的编码不同,PowerShell 误解 输出。

要解决此问题,您必须(暂时)设置 [Console]::OutputEncoding] 以匹配外部程序使用的编码

例如,我们假设一个输出 UTF-8 编码文本的可执行文件 foo.exe:

# Save the current encoding and switch to UTF-8.
$prev = [Console]::OutputEncoding
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()

# PowerShell now interprets foo's output correctly as UTF-8-encoded.
# and $output will correctly contain CJK characters.
$output = foo https://example.org -e

# Restore the previous encoding.
[Console]::OutputEncoding = $prev

重要:

  • [Console]::OutputEncoding 默认情况下 反射(reflect)了与遗留系统区域设置的 OEM 代码页 关联的编码,如所报告的通过 chcp(例如美国英语系统上的 437)。

    • 最新版本的 Windows 10 现在允许将系统区域设置设置为代码页 65001 (UTF-8)(自 Window 10 版本 1909 起,该功能仍处于测试阶段),这很好,考虑到大多数现代命令行实用程序“使用”UTF-8 - 但请注意,进行系统范围更改已经很远-达到后果 - 参见this answer .

根据手头的具体程序,youtube-dl , js2010 has discovered如果您通过 --encoding utf-16,则在变量中捕获无需额外的努力。

之所以可行,是因为生成的 UTF16-LE 编码输出前面有 BOM(字节顺序标记)。

(请注意,--encoding utf-8 起作用,因为 youtube-dl > 发出 BOM。)

Windows PowerShell 能够检测并正确解码 UTF-16LE 编码和 UTF-8 编码的文本而不管有效的[Console]::OutputEncoding] 当且仅当输出前面有 BOM。

注意事项:

  • 这在 PowerShell Core(v6+,在任何支持的平台上)中有效。

  • 即使在 Windows PowerShell 中,您也很少能够利用这种模糊的行为,因为在stdout 输出 中使用 BOM 是非典型(它是通常仅用于文件)。

关于使用 UTF-8 编码的 Powershell 字符串变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58438095/

相关文章:

powershell - HTMLagilityPack 结合 Powershell、Windows 身份验证

java - 进程输入流中丢失的特殊字符

c++ - 任务管理器是 Windows 10 的一种特殊类型的 'Always on Top' 窗口吗?

node.js - 如何理解utf8编码文本中的文本语言?

php - 从 php 发送邮件 - 字符集编码

javascript - 我可以从 Windows 10 (UWP) 应用程序中的 Web Worker 调用自定义运行时组件吗

registry - Windows 10 平板电脑模式注册表设置 : 'When this device automatically switches tablet mode on or off'

powershell - 当你想显示多列时,如何在 powershell 中展开 ...?

multithreading - 在以 Start-ThreadJob 启动的线程中使用作用域变量修改 PowerShell $

powershell - 使用 Powershell 在同一数组中重新组合常见项目值