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

Powershell string variable with UTF-8 encoding

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

例如,我正在尝试下载 YouTube 视频。如果我们打印视频标题,就会显示 non-English 个字符(ytd 这里是 youtube-dl):

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

输出:[LEEPLAY] 시티팝 입문 City Pop MIX (Playlist)

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

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

$vtitle

输出:[LEEPLAY] City Pop MIX (Playlist)

有关 PowerShell 如何与外部程序交互的全面概述,其中包括将数据发送到[=109] =]他们,见.

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

注:

  • Interpreting 是指 PowerShell captures(例如,$output = ...),relays(例如,... | Select-String ...),或 redirects(例如,... > output.txt)外部程序的输出。

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

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

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

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

# 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 默认情况下 反映与遗留系统区域设置的 OEM 代码页 关联的编码,如 chcp 所报告(例如 437 在美式英语系统上)。

    • Windows10 的最新版本现在允许将系统区域设置设置为代码页 65001 (UTF-8)(该功能仍处于测试阶段从 Window 10 版本 1909 开始),这很好,考虑到 大多数现代命令行实用程序“说” UTF-8 - 但请注意使 全系统 更改具有深远的影响 - 请参阅

使用手头的特定程序,youtube-dl, 如果您通过 --encoding utf-16.

,则在变量中捕获无需额外的努力

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

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

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

注意事项:

  • 在 PowerShell Core(v6+,在任何支持的平台上)中工作。

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

这在 ISE 中对我有用。 Youtube-dl 来自 ytdl-org.github.io。实际上不需要ise,但是文件名只会在资源管理器之类的东西中正确显示。

# get title
# utf-16 has a bom, or use utf-8-sig, this program is python based
$a = .\youtube-dl -e https://www.youtube.com/watch?v=Qpy7N4oFQUQ --encoding utf-16
$a
Gacharic Spin - 赤裸ライアー教則映像(short ver.)TOMO-ZO編

您可能在 vscode(或 osx/linux)中有类似的运气。