将 System.UInt16 数组转换为字符串
Converting a System.UInt16 array to a string
我遇到了一个奇怪的问题,我需要删除可能不是 space 或标签的 "blank characters"。
这是来自WMI的信息。 "SerialNumberID" 属性 存储为 UInt16[] 数组。
我是这样收集的:
$SERIAL = (Get-WmiObject -ComputerName XXXX WmiMonitorID -Namespace root\wmi ).SerialNumberID
现在包含以下数组:
72
86
76
81
66
48
50
53
52
50
0
0
0
0
0
0
要将其转换为可读格式,我正在做:
$SERIAL_AS_STRING = [System.Text.Encoding]::Default.GetString($SERIAL)
"+$SERIAL_AS_STRING+"
(我用+号方便识别数据后是否有字符)
这个returns:
+HVLQB02542 +
我只想得到序列号,所以我想像这样去掉 spaces:
$SERIAL_AS_STRING = $SERIAL_AS_STRING.Trim()
"+$SERIAL_AS_STRING+"
它仍然 returns 有空白 spaces! :
+HVLQB02542 +
即使我尝试类似的方法:
$SERIAL_AS_STRING = $SERIAL_AS_STRING -replace '(^\s+|\s+$)','' -replace '\s+',' '
space总是在那里。
现在我看到在 System.UInt16 数组中我有六个尾随零,这恰好与我结果字符串中的六个尾随 spaces 相符....
所以我尝试了一种不同的方法来转换数组,即:
$SERIAL2 = ($SERIAL -notmatch 0 | ForEach{[char]$_}) -join ""
"+$SERIAL2+"
这可以删除尾随的 spaces 但是这是不可接受的,因为它会像这样弄乱序列:
+HVLQB054+
应该是:+HVLQB02542+
我在这里做错了什么?很奇怪,如果我特别要求更换六个 spaces,它也不起作用。这就是为什么我怀疑这些 "spaces" 不是真正的 space 字符!
目前,我使用 RegEx 使其工作,它会删除所有非字母或数字的内容:
$FINAL = $SERIAL_AS_STRING -replace "[^A-Za-z0-9]"
但是如何正确完成它,因为这感觉像是一种变通解决方案?
编辑:在下面用户 TrebleCode 的帮助下,我能够将违规字符识别为像这样的 Ascii 代码 0 字符 [byte][char]$SERIAL_AS_STRING[16]
。这返回了 0,所以现在我知道我必须用任何东西替换 Ascii 代码 0。
我是这样解决的:
$ascii0 = [char]0
$FinalString = $SERIAL_AS_STRING -replace $ascii0,""
"+$FinalString+"
+HVLQB02542+
啊,没有更多的垃圾空白字符:) ASCII 代码 0 实际上是 0 NUL(空),而代码 32 是 Space.
您可以通过转换 space 字符之一的类型并检查 ASCII 代码来检查它们是否实际上是 space:
$a = '+HVLQB02542 +'
获取倒数第二个字符并检查它的 return 值:
[byte][char]$a[16]
which returns 32
,这是一个space
的ASCII码
使用 -replace
运算符的另一种方法,如果去掉最后两个单引号之间的 space,您应该得到所需的结果:
$a -replace '(^\s+|\s+$)','' -replace '\s+',''
return秒:+HVLQB02542+
你也可以这样做 $a.replace(' ','')
并且应该产生与上面相同的结果
虽然 $a
最初将 return 作为 UInt16[]
,但我在尝试执行 [System.Text.Encoding]::Default.GetString($a)
时遇到错误
.SerialNumberID
输出的是一个 int [uint16[]]
数组(参见 the docs)。
如果您想将这些 uint16
实例转换为 字符串,您可以简单地将它们 直接 解释为 Unicode UTF -16 代码点(Unicode 等同于 ASCII 码,它是超集),这就是字符 ([char]
) 实例在 .NET 内存中的表示方式.
因此,您可以 简单地转换为 [char[]]
并加入 -join
结果字符数组以形成 [string]
.
(也就是说,不需要 [System.Text.Encoding]::Default.GetString()
,顺便说一句,会将这些值解释为 字节 .[1])
您的 .SerialNumberID
有尾随 0
个实例,但是 [char[]]
和 [System.Text.Encoding]::Default.GetString()
在转换中保留 ,作为 NUL
个字符。
您可以 删除不需要的 0
/ NUL
实例,只需在转换前使用 -ne 0
从输入数组中过滤掉它们.
总而言之:
# Simulate the result of your (Get-WmiObject ...).SerialNumberID call
$SERIAL = [uint16[]] (72, 86, 76, 81, 66, 48, 50, 53, 52, 50, 0, 0, 0, 0, 0, 0)
$SERIAL_AS_STRING = -join [char[]] ($SERIAL -ne 0)
# Show the resulting string
"+$SERIAL_AS_STRING+"
以上结果 +HVLQB02542+
,如您所愿。
[1] 只有当输入数组表示 UTF-16 以外的特定字符编码时,您才需要适当的 [System.Text.Encoding]
实例的 .GetString()
方法;请注意,该方法需要一个 [byte[]]
数组,虽然 PowerShell 将尝试自动将 [uint16[]]
强制转换为该数组,但如果任何数组元素,这样做将 失败 具有大于 255
(0xFF
) 的值,即太大而无法放入 [byte]
.
类似的说明...将 System.UInt16[] 数组转换为整数示例:
$rv=(Get-CIMInstance Win32_SystemEnclosure).ChassisTypes;
[int]$as= -join [int[]] ($rv -ne 0);
我遇到了一个奇怪的问题,我需要删除可能不是 space 或标签的 "blank characters"。
这是来自WMI的信息。 "SerialNumberID" 属性 存储为 UInt16[] 数组。
我是这样收集的:
$SERIAL = (Get-WmiObject -ComputerName XXXX WmiMonitorID -Namespace root\wmi ).SerialNumberID
现在包含以下数组:
72
86
76
81
66
48
50
53
52
50
0
0
0
0
0
0
要将其转换为可读格式,我正在做:
$SERIAL_AS_STRING = [System.Text.Encoding]::Default.GetString($SERIAL)
"+$SERIAL_AS_STRING+"
(我用+号方便识别数据后是否有字符)
这个returns:
+HVLQB02542 +
我只想得到序列号,所以我想像这样去掉 spaces:
$SERIAL_AS_STRING = $SERIAL_AS_STRING.Trim()
"+$SERIAL_AS_STRING+"
它仍然 returns 有空白 spaces! :
+HVLQB02542 +
即使我尝试类似的方法:
$SERIAL_AS_STRING = $SERIAL_AS_STRING -replace '(^\s+|\s+$)','' -replace '\s+',' '
space总是在那里。
现在我看到在 System.UInt16 数组中我有六个尾随零,这恰好与我结果字符串中的六个尾随 spaces 相符....
所以我尝试了一种不同的方法来转换数组,即:
$SERIAL2 = ($SERIAL -notmatch 0 | ForEach{[char]$_}) -join ""
"+$SERIAL2+"
这可以删除尾随的 spaces 但是这是不可接受的,因为它会像这样弄乱序列:
+HVLQB054+
应该是:+HVLQB02542+
我在这里做错了什么?很奇怪,如果我特别要求更换六个 spaces,它也不起作用。这就是为什么我怀疑这些 "spaces" 不是真正的 space 字符!
目前,我使用 RegEx 使其工作,它会删除所有非字母或数字的内容:
$FINAL = $SERIAL_AS_STRING -replace "[^A-Za-z0-9]"
但是如何正确完成它,因为这感觉像是一种变通解决方案?
编辑:在下面用户 TrebleCode 的帮助下,我能够将违规字符识别为像这样的 Ascii 代码 0 字符 [byte][char]$SERIAL_AS_STRING[16]
。这返回了 0,所以现在我知道我必须用任何东西替换 Ascii 代码 0。
我是这样解决的:
$ascii0 = [char]0
$FinalString = $SERIAL_AS_STRING -replace $ascii0,""
"+$FinalString+"
+HVLQB02542+
啊,没有更多的垃圾空白字符:) ASCII 代码 0 实际上是 0 NUL(空),而代码 32 是 Space.
您可以通过转换 space 字符之一的类型并检查 ASCII 代码来检查它们是否实际上是 space:
$a = '+HVLQB02542 +'
获取倒数第二个字符并检查它的 return 值:
[byte][char]$a[16]
which returns 32
,这是一个space
使用 -replace
运算符的另一种方法,如果去掉最后两个单引号之间的 space,您应该得到所需的结果:
$a -replace '(^\s+|\s+$)','' -replace '\s+',''
return秒:+HVLQB02542+
你也可以这样做 $a.replace(' ','')
并且应该产生与上面相同的结果
虽然 $a
最初将 return 作为 UInt16[]
[System.Text.Encoding]::Default.GetString($a)
时遇到错误
.SerialNumberID
输出的是一个 int [uint16[]]
数组(参见 the docs)。
如果您想将这些 uint16
实例转换为 字符串,您可以简单地将它们 直接 解释为 Unicode UTF -16 代码点(Unicode 等同于 ASCII 码,它是超集),这就是字符 ([char]
) 实例在 .NET 内存中的表示方式.
因此,您可以 简单地转换为 [char[]]
并加入 -join
结果字符数组以形成 [string]
.
(也就是说,不需要 [System.Text.Encoding]::Default.GetString()
,顺便说一句,会将这些值解释为 字节 .[1])
您的 .SerialNumberID
有尾随 0
个实例,但是 [char[]]
和 [System.Text.Encoding]::Default.GetString()
在转换中保留 ,作为 NUL
个字符。
您可以 删除不需要的 0
/ NUL
实例,只需在转换前使用 -ne 0
从输入数组中过滤掉它们.
总而言之:
# Simulate the result of your (Get-WmiObject ...).SerialNumberID call
$SERIAL = [uint16[]] (72, 86, 76, 81, 66, 48, 50, 53, 52, 50, 0, 0, 0, 0, 0, 0)
$SERIAL_AS_STRING = -join [char[]] ($SERIAL -ne 0)
# Show the resulting string
"+$SERIAL_AS_STRING+"
以上结果 +HVLQB02542+
,如您所愿。
[1] 只有当输入数组表示 UTF-16 以外的特定字符编码时,您才需要适当的 [System.Text.Encoding]
实例的 .GetString()
方法;请注意,该方法需要一个 [byte[]]
数组,虽然 PowerShell 将尝试自动将 [uint16[]]
强制转换为该数组,但如果任何数组元素,这样做将 失败 具有大于 255
(0xFF
) 的值,即太大而无法放入 [byte]
.
类似的说明...将 System.UInt16[] 数组转换为整数示例:$rv=(Get-CIMInstance Win32_SystemEnclosure).ChassisTypes;
[int]$as= -join [int[]] ($rv -ne 0);