1

我遇到了一个奇怪的问题,我需要删除可能不是空格或制表符的“空白字符”。

这是来自 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+"

(我使用 + 字符来轻松识别数据后是否有字符)

这返回:

+HVLQB02542      +

我只想拥有序列号,所以我试图摆脱这样的空格:

$SERIAL_AS_STRING = $SERIAL_AS_STRING.Trim()

"+$SERIAL_AS_STRING+"

它仍然返回空格!:

+HVLQB02542      +

即使我尝试类似:

$SERIAL_AS_STRING = $SERIAL_AS_STRING -replace '(^\s+|\s+$)','' -replace '\s+',' '

空间总是在那里。

现在我看到在 System.UInt16 数组中我有六个尾随零,它与我的结果字符串中的六个尾随空格完全吻合......

所以我尝试了一种不同的方法来转换数组:

$SERIAL2 = ($SERIAL -notmatch 0 | ForEach{[char]$_}) -join ""

"+$SERIAL2+"

这可以删除尾随空格,但这是不可接受的,因为它会像这样弄乱序列:

+HVLQB054+

应该是:+HVLQB02542+

我在这里做错了什么?这很奇怪,因为如果我特别要求替换六个空格,它也不起作用。这就是为什么我怀疑这些“空格”不是真正的空格字符!

现在我通过使用 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(Null),而代码 32 是空格。

4

3 回答 3

2

.SerialNumberID输出的是一个 int数组[uint16[]](参见文档)。

如果您想将这些uint16实例转换为字符串,您可以简单地将它们直接解释为 Unicode UTF-16代码点(ASCII 代码的 Unicode 等价物,它是它的超集),这就是字符 ( [char]) 实例的表示方式在 .NET 的内存中。

因此,您可以简单地转换[char[]]并加入-join结果字符数组以形成[string].

(也就是说,不需要[System.Text.Encoding]::Default.GetString()顺便说一下,它将值解释为bytes[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以外的特定字符编码时,才需要.GetString()相应[System.Text.Encoding]实例的方法;请注意,该方法需要一个[byte[]]数组,虽然 PowerShell 将尝试自动强制 a ,但如果任何数组元素的值大于( ),则[uint16[]]这样做将失败,即太大而无法放入 a 。2550xFF[byte]

于 2019-03-01T20:52:00.070 回答
1

在类似的注释...将 System.UInt16[] 数组转换为整数示例:
$rv=(Get-CIMInstance Win32_SystemEnclosure).ChassisTypes; [int]$as= -join [int[]] ($rv -ne 0);

于 2019-07-02T18:38:26.853 回答
1

您可以通过转换其中一个空格字符的类型并检查 ASCII 代码来检查这些是否实际上是空格:

$a = '+HVLQB02542      +'

获取倒数第二个字符并检查它的返回值:

[byte][char]$a[16]

返回32,这是空格的 ASCII 码

使用使用-replace运算符的另一种方法,如果去掉最后两个单引号之间的空格,最终应该会得到所需的结果:

$a -replace '(^\s+|\s+$)','' -replace '\s+',''

返回:+HVLQB02542+

你也可以做$a.replace(' ','')并且应该产生与上面相同的结果

[System.Text.Encoding]::Default.GetString($a)虽然$a最初确实以 UInt16[] 的形式返回,但尝试执行时出现错误

于 2019-03-01T18:30:44.930 回答