Преобразование массива System.UInt16 в строку - PullRequest
0 голосов
/ 01 марта 2019

У меня странная проблема, когда мне нужно удалить "пустые символы", которые, вероятно, не являются пробелами или табуляциями.

Это информация из 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 у меня естьКонечные нули SIX, которые точно соответствуют концевым пробелам SIX в моей строке результата ....

Поэтому я попробовал другой метод для преобразования массива:

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

"+$SERIAL2+"

Это работаетудалить пробелы, однако это неприемлемо, потому что портит сериал следующим образом:

+HVLQB054+

Что должно быть: +HVLQB02542+

Что я здесь не так делаю?Это странно, потому что, если я специально прошу заменить пробелы SIX, это тоже не сработает.Вот почему я подозреваю, что эти "пробелы" на самом деле не являются пробелами!

Пока я заставляю его работать с помощью RegEx, который удаляет все, что не является буквой или цифрой:

$FINAL = $SERIAL_AS_STRING -replace "[^A-Za-z0-9]"

Но как это можно сделать правильно, так как это похоже на временное решение?

РЕДАКТИРОВАТЬ: С помощью пользователя TrebleCode ниже, я смог идентифицировать оскорбительные символы как код Ascii0 символов, как это [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, который является пробелом.

Ответы [ 3 ]

0 голосов
/ 01 марта 2019

Что .SerialNumberID выводит массив типа int [uint16[]] (см. документы ).

Если вы хотите преобразовать эти 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, для которой требуется метод .GetString() соответствующего экземпляра [System.Text.Encoding];обратите внимание, что для этого метода требуется массив [byte[]], и в то время как PowerShell попытается автоматически принудительно установить [uint16[]] на это, при этом не удастся , если какой-либо из элементов массива будет иметь значение больше 255(0xFF), то есть слишком велики, чтобы поместиться в [byte].

0 голосов
/ 02 июля 2019

На похожую заметку ... Конвертировать массив System.UInt16 [] в целочисленный пример:$rv=(Get-CIMInstance Win32_SystemEnclosure).ChassisTypes; [int]$as= -join [int[]] ($rv -ne 0);

0 голосов
/ 01 марта 2019

Вы можете проверить, действительно ли это пробелы, преобразовав тип одного из пробелов и проверив код 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 []

...