1
votes

Conversion d'un tableau System.UInt16 en chaîne

Je rencontre un problème étrange où je dois supprimer des "caractères vides" qui ne sont probablement pas des espaces ou des tabulations.

Ce sont des informations provenant de WMI. La propriété "SerialNumberID" est stockée sous la forme d'un UInt16 [] Array.

Je la rassemble comme ceci:

$ascii0 = [char]0
$FinalString = $SERIAL_AS_STRING -replace $ascii0,""


"+$FinalString+"

+HVLQB02542+

Il contient maintenant le tableau suivant:

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

Pour convertir cela en un format lisible, je fais:

+HVLQB054+

(j'utilise le caractère + pour identifier facilement s'il y a des caractères après les données)

Ceci renvoie:

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

"+$SERIAL2+"

Je veux avoir juste le numéro de série, donc j'essaye pour se débarrasser des espaces comme ceci:

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

et il revient TOUJOURS avec les espaces vides! :

+HVLQB02542      +

Même si j'essaye quelque chose comme:

$SERIAL_AS_STRING = $SERIAL_AS_STRING.Trim()

"+$SERIAL_AS_STRING+"

les espaces sont toujours là.

Maintenant, je vois que dans le tableau System.UInt16, j'ai SIX zéros de fin, qui correspondent précisément aux espaces de fin SIX dans ma chaîne de résultat ....

J'ai donc essayé une méthode différente pour convertir le tableau ce qui est:

+HVLQB02542      +

Cela fonctionne pour supprimer les espaces de fin, mais il est inaceptable car cela gâche la série comme ceci:

$SERIAL_AS_STRING = [System.Text.Encoding]::Default.GetString($SERIAL)

"+$SERIAL_AS_STRING+"

Ce qui devrait être: +HVLQB02542+

Qu'est-ce que je fais de mal ici? C'est étrange parce que si je demande spécialement à remplacer SIX espaces, cela ne fonctionne pas non plus. C'est pourquoi je soupçonne que ces "espaces" ne sont pas vraiment des espaces!

Pour l'instant, je le fais fonctionner en utilisant RegEx, qui supprime tout ce qui n'est pas des lettres ou des chiffres:

72
86
76
81
66
48
50
53
52
50
0
0
0
0
0
0

Mais comment cela peut-il être fait correctement, car cela ressemble à une solution de contournement?

MODIFIER: Avec l'aide de l'utilisateur TrebleCode ci-dessous, j'ai pu pour identifier les caractères incriminés comme des caractères de code Ascii 0 comme ceci [byte] [char] $ SERIAL_AS_STRING [16] . Cela a renvoyé 0 alors maintenant je savais que je devais remplacer le code Ascii 0 par rien.

Voici comment je l'ai résolu:

$SERIAL = (Get-WmiObject -ComputerName XXXX WmiMonitorID -Namespace root\wmi ).SerialNumberID

Ahhh plus de caractères vides inutiles :) Le code ASCII 0 est en fait 0 NUL (Null), comparé au code 32 qui est Space.


1 commentaires

Veuillez publier votre solution en tant que réponse (et l'accepter si vous pensez que c'est la meilleure réponse pour les futurs lecteurs.)


3 Réponses :


1
votes

Vous pouvez vérifier s'il s'agit ou non d'espaces en convertissant le type de l'un des caractères d'espacement et en vérifiant le code ASCII:

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

Récupérez l'avant-dernier caractère et vérifiez c'est la valeur de retour:

[byte][char]$a[16]

qui renvoie 32 , qui est le code ASCII d'un espace

Avec l'autre méthode vous eu en utilisant l'opérateur -replace , si vous supprimez l'espace entre les deux derniers guillemets simples, vous devriez vous retrouver avec le résultat souhaité:

$a = '+HVLQB02542      +'

renvoie: +HVLQB02542+

Vous pouvez également faire $ a.replace ('', '') et devrait donner le même résultat que ci-dessus p>

J'obtiens des erreurs en essayant de faire [System.Text.Encoding] :: Default.GetString ($ a) bien que $ a retourne initialement comme un UInt16 []


3 commentaires

Hmm merci pour l'aide, mais ce n'est pas 32, il renvoie 0. Si vous copiez coller de mon message, je parie qu'il reviendra sous forme d'espace (32) mais lorsque j'exécute les commandes, [byte] [char] $ SERIAL_AS_STRING [16 ] renvoie le code ASCII 0 pour que tout le code que vous donnez comme exemple ne fonctionne pas. Je suppose que ma question est de savoir comment puis-je utiliser -replace et spécifier une valeur de code ASCII à remplacer?


Cet article précédent suggère quelques options qui pourraient fonctionner: stackoverflow.com/questions/15343442/...


Grâce à votre aide pour m'éveiller au code ascii, j'ai trouvé la solution de travail! Vérifiez la modification de ma question. Le crédit vous revient hehe



2
votes

Ce que .SerialNumberID produit est un tableau int [uint16 []] (voir les documents ).

Si vous souhaitez convertir ces instances uint16 en une chaîne em>, vous pouvez simplement les interpréter directement comme des points de code Unicode UTF-16 (l'équivalent Unicode d'un code ASCII, dont il est un sur-ensemble), c'est ainsi les instances de caractères ( [char] ) sont représentées en mémoire dans .NET.

Ainsi, vous pouvez simplement convertir en [char []] code > et joignez -join le tableau de caractères résultant pour former une [chaine ] final.

(Autrement dit, il y a pas besoin de [System.Text.Encoding] :: Default.GetString () , qui, incidemment, interpréterait les valeurs comme octets . [1] )

Votre .SerialNumberID a des instances 0 de fin, cependant, qui à la fois [char []] et [System.Text.Encoding] :: Default.GetString () conservent dans la conversion, comme NUL caractères.

Vous pouvez supprimer les instances 0 / NUL indésirables en les filtrant simplement du tableau d'entrée avec -ne 0 avant la conversion.

Pour tout rassembler:

# 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+"

Ce qui précède donne + HVLQB02542 + , comme vous le souhaitez.


[1] Ce n'est que si le tableau d'entrée représente un encodage de caractères spécifique autre que UTF-16 que vous avez besoin du . GetString () de l'instance [System.Text.Encoding] appropriée; notez que cette méthode nécessite un tableau [byte []] , et tandis que PowerShell essaiera de forcer automatiquement un [uint16 []] à cela, cela échouer si l'un des éléments du tableau a une valeur supérieure à 255 ( 0xFF ), c'est-à-dire qu'il est trop grand pour tenir dans un [octet] .


1 commentaires

@Rakha: Mon plaisir. C'est moi qui ai signalé votre commentaire comme n'étant plus nécessaire, et un modérateur l'a supprimé en conséquence. Pour être clair, j'ai vraiment apprécié vos bons commentaires; puisque j'ai perçu votre commentaire comme un remerciement personnel, j'ai pensé qu'il avait atteint son objectif une fois que je l'avais lu. Pour les futurs lecteurs, seuls les commentaires contenant des informations techniques sont intéressants. De même, si je devais vous remercier vous dans un commentaire à l'avenir ou répondre à nouveau à un merci de votre part, je vous encourage à signaler ce commentaire comme n'étant plus nécessaire après l'avoir lu - y compris ceci un.



1
votes

Sur une note similaire ... Exemple de conversion du tableau System.UInt16 [] en nombre entier:
$ rv = (Get-CIMInstance Win32_SystemEnclosure) .ChassisTypes; [int] $ as = -join [int []] ($ rv -ne 0);


1 commentaires

Conseil utile! Pouvez-vous expliquer ce que fait l'int [] après la jointure?