首页 > 解决方案 > 将 PowerShell(欧洲)中的字符串转换为 UTF-8

问题描述

对于 REST 调用,我需要 UTF-8 中的德语“Stück”从访问数据库中读取

$conn = New-Object System.Data.OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$filename;Persist Security Info=False;")

并尝试转换它。我发现 PowerShell ISE 似乎在 ANSI 中编码字符串常量。因此,我尝试在没有数据库的情况下进行最低限度的测试,并得到了相同的结果:

$Text1 = "Stück" # entered via ISE, this is also what I get from the database
# ($StringFromDatabase -eq $Test1) shows $true

$enc = [System.Text.Encoding]::GetEncoding(1252).GetBytes($Text1)
# also tried [System.Text.Encoding]::GetEncoding("ISO-8859-1") # = 28591

$Text1 = [System.Text.Encoding]::UTF8.GetString($enc)

$Text1
$Text1 = "Stück" # = UTF-8, entered here with Notepad++, encoding set to UTF-8
"must see: $Text1"

所以我得到了两个输出——转换后的一个(显示“St?ck”),但我需要看到“Stück”。

标签: stringpowershellutf-8oledbconnection

解决方案


PowerShell ISE 似乎在ANSI中编码字符串常量。

仅适用于与外部程序通信,而您使用的是进程内 .NET API。

顺便说一句:与使用活动OEM代码页的常规控制台窗口的这种差异是导致过时 ISE 出现问题的原因之一 - 请参阅此答案的底部以获取更多信息。

内存中的字符串文字始终是 .NET 字符串,它们是 UTF-16 编码的(由 16 位 Unicode 代码单元组成),能够表示所有Unicode 字符[1]


Web 服务调用( Invoke-RestMethod, )中的字符编码Invoke-WebRequest

发送UTF-8 字符串,请指定charset=utf-8-ContentType参数的一部分;例如:

Invoke-RestMethod -ContentType 'text/plain; charset=utf-8' ...

接收字符串时,PowerShell 会根据响应内容标头中明确指定的字段(字符编码)自动解码它们,或者charset在没有它的情况下使用 ISO-8859-1(与 Windows-8859-1 密切相关,但实际上是Windows的一个子集) 1252)。

  • 如果给定的响应没有指定 acharset但实际上使用了与 ISO-8859-1不同的编码 - 比如说 UTF-8 - PowerShell 将误解收到的字符串,这需要事后重新编码- 请参阅此答案

与外部程序通信时的字符编码:

如果您需要将具有特定编码的字符串发送到外部程序(通过管道,目标程序通过 stdin 接收),请将$OutputEncoding首选项变量设置为该编码,PowerShell 会自动将您的 .NET 字符串转换为指定的编码.

通过管道将 UTF-8 编码的字符串发送到外部程序

$OutputEncoding = [System.Text.UTF8Encoding]::new()

但是请注意,仅此一项还不足以正确接收来自外部程序的 UTF-8 输出;为此,您需要设置[Console]::OutputEncoding为相同的编码。

要使您的 PowerShell 会话完全支持 UTF-8(无论是在 ISE 还是常规控制台窗口中):

# Needed in the ISE only:
chcp >$null # Dummy console-program call that ensures that a console is allocated.

# Set all encodings relevant to communicating with external programs to UTF-8.
$OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding =
  [System.Text.UTF8Encoding]::new()

有关更多信息,请参阅此答案


[1] 但是请注意,代码点大于 的 Unicode 字符0xFFFF,即所谓的 BMP(基本多语言平面)之外的字符,必须用两个16 位代码单元 ( [char]) 表示,即所谓的代理对.


推荐阅读