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 代码点,0xc3b1
和 0xc391
,实际上是 2 字节 UTF-8 编码(0xc3 0xb1
和0xc3 91
)对应ñ
和Ñ
的真码点:0xf1
and 0xd1
至于:
[convert]::toChar(0x91)
看似不是生成具有给定代码点的[char]
实例,0x91
(十进制145
):
它做,即在内存中,你可以很容易地验证:
[int] [convert]::toChar(0x91) # -> 145 (0x91)
你只会得到 0x3f
- 这是一个文字 ?
字符(尝试 [char] 0x3f
) - 如果你错误地保存了内存中的表示ASCII 编码:由于 0x91
在 Unicode 的 ASCII 子范围之外(从 0x00
到 0x7f
),它不能在输出文件中表示,并且 替换字符 ?
被使用。
请注意,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
。
我正在尝试创建一个 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 代码点,0xc3b1
和 0xc391
,实际上是 2 字节 UTF-8 编码(0xc3 0xb1
和0xc3 91
)对应ñ
和Ñ
的真码点:0xf1
and 0xd1
至于:
[convert]::toChar(0x91)
看似不是生成具有给定代码点的[char]
实例,0x91
(十进制145
):
它做,即在内存中,你可以很容易地验证:
[int] [convert]::toChar(0x91) # -> 145 (0x91)
你只会得到
0x3f
- 这是一个文字?
字符(尝试[char] 0x3f
) - 如果你错误地保存了内存中的表示ASCII 编码:由于0x91
在 Unicode 的 ASCII 子范围之外(从0x00
到0x7f
),它不能在输出文件中表示,并且 替换字符?
被使用。
请注意,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
。