Powershell,无法输入带有某些非 ASCII 字符的哈希表键(在脚本中)

Powershell, can't enter hashtable keys with some non-ASCII characters (in a script)

我正在尝试创建一个 PowerShell 散列 table 以将非 ASCII (UTF8) 字符转换为其类似的 ASCII。

这里有两个散列 table 条目作为示例:'ñ'='n''Ñ'='N'

编者注:在 same 散列 table 文字中使用 both 这些条目(@{ 'ñ'='n'; 'Ñ'='N' }) 不起作用,因为 PowerShell 使用散列 tables 和大小写 不敏感 键查找,因此考虑 'ñ''Ñ'重复 键和抱怨。但是,这是手头问题的偶然

第一个有效:'ñ'0xc3b1。第二个不起作用:'Ñ'0xc391,PowerShell 不会接受。 (问题似乎是 0x91 超出了 acceptable powershell 字符的范围。)

问题的一个更简单的例子是:

$c = [convert]::toChar(0x91)

这导致 $c 得到 0x3f 而不是 0x91 的值。那么我该怎么做才能让 'Ñ'='N' 进入 散列 table 或值为 0x91 的字符?我已经花了几个小时阅读网页和进行试验。

注意:默认情况下,PowerShell 哈希tables,由于使用大小写不敏感 查找,不支持仅 大小写的键另一个的变体;因此,ñÑ - 前者是后者的小写版本 - 不能 both 用作键 - 见底部。


内存中,所有PowerShell字符串都是UTF-16 .NET字符串,能够表示所有 Unicode 字符 ,因此使用 Ñ 等字符作为散列 table 中的键 不是 问题。

您描述的问题仅在 PowerShell 误解源代码从文件读取时出现, 由于假定了错误的字符编码。

您的症状表明您的源代码是 UTF-8 编码的,但文件 没有 BOM,这导致 Windows PowerShell(但幸运的是,不再是 PowerShell [Core] v6+)将文件误解为根据系统的活动遗留 ANSI 代码页编码的文件(例如,Windows-1252 在美式英语系统上), 单字节编码。

确保您的源代码文件保存为 UTF-8 带 BOM[1] ,你的问题就会消失。

你认为的 Unicode 代码点,0xc3b10xc391,实际上是 2 字节 UTF-8 编码(0xc3 0xb10xc3 91)对应ñÑ的真码点:0xf1 and 0xd1


至于:

[convert]::toChar(0x91)

看似不是生成具有给定代码点的[char]实例,0x91(十进制145):

  • ,即在内存中,你可以很容易地验证:

      [int] [convert]::toChar(0x91) # -> 145 (0x91)
    
  • 你只会得到 0x3f - 这是一个文字 ? 字符(尝试 [char] 0x3f) - 如果你错误地保存了内存中的表示ASCII 编码:由于 0x91 在 Unicode 的 ASCII 子范围之外(从 0x000x7f),它不能在输出文件中表示,并且 替换字符 ?被使用。


请注意,PowerShell 的散列 table 不区分大小写,因此您不能拥有密钥这仅仅是 大小写变化 彼此:

# !! FAILS
PS> @{ Ñ = 'LATIN CAPITAL LETTER N WITH TILDE'; ñ = 'LATIN SMALL LETTER N WITH TILDE' }
...  Duplicate keys 'ñ' are not allowed in hash literals.

您必须直接使用 .NET [hashtable] 类型 (System.Collections.Hashtable) 来创建大小写-敏感哈希 tables:

# Create case-SENSITIVE hash table:
$ht = [hashtable]::new()
$ht['ñ'] = 'LATIN SMALL LETTER N WITH TILDE' 
$ht['Ñ'] = 'LATIN CAPITAL LETTER N WITH TILDE'
  • $ht 现在有 2 个条目,$ht['ñ']$ht['Ñ'] 检索区分大小写的值。

  • 相比之下,如果您使用了 $ht = @{},即将散列 table 初始化为常规的大小写 不敏感 散列table,你只会得到 1 条目,值为 'LATIN CAPITAL LETTER N WITH TILDE',因为第二个赋值 $ht['Ñ'] =,只是 updated 第一条语句创建的不区分大小写的查找键。


[1] 或者,使用 UTF-16 编码,总是 使用 BOM; UTF-16LE 格式在 PowerShell 中被(错误地)称为 Unicode