3 votes

Diviser les données binaires en un tableau d'octets en Perl

Je voulais essentiellement convertir une chaîne binaire en un tableau/liste d'octets (afin de permettre l'indexation et d'éviter d'utiliser substr, car sa syntaxe complique les choses pour moi), et j'ai trouvé le MWE suivant :

#!/usr/bin/env perl

use warnings;
use strict;

# Use open ':raw';      # Unknown PerlIO layer class ':raw'
use open IO => ':raw';

binmode(STDIN);
binmode(STDOUT);

# Create original 8-bit byte array/list
my @atmp = (0x80, 0x23, 0x14, 0x0d, 0x0a, 0x00, 0x00, 0x80, 0x43, 0x00, 0x00);

# Make a copy of portion
my @atmp2 = (0) x 2;
@atmp2[0..1] = @atmp[7..8];

# Print output
print "Copied atmp2 contents as hex: " . join(", ", unpack("H2"x2, pack("C"x2,@atmp2))) . "\n";
print "Copied atmp2 as ushort (16bit) int: " . unpack("S", pack("C"x2, @atmp2));
# doublecheck value by routing through printf with format specifier:
printf(" [%d]\n", unpack("S", pack("C"x2, @atmp2));

# Now, the same data as string:
my $indata = "\x80\x23\x14\x0d\x0a\x00\x00\x80\x43\x00\x00";

# Create byte array (by converting string $indata to array/list with `split`)
my @btmp = split('',$indata);
print "lastindex: " . $#btmp . "\n";

# Make a copy of portion
my @btmp2 = (0) x 2;
@btmp2[0..1] = @btmp[7..8];

# Print output
print "Copied btmp2 contents as hex: " . join(", ", unpack("H2"x2, pack("C"x2,@btmp2))) . "\n";
print "Copied btmp2 as ushort (16bit) int: " . unpack("S", pack("C"x2, @btmp2));
# doublecheck value by routing through printf with format specifier:
printf(" [%d]\n", unpack("S", pack("C"x2, @btmp2)));

L'exécution de ce code donne :

$ perl test.pl
Copied atmp2 contents as hex: 80, 43
Copied atmp2 as ushort (16bit) int: 17280 [17280]
lastindex: 10
Argument "M-\0" isn't numeric in pack at test.pl line 38.
Argument "C" isn't numeric in pack at test.pl line 38.
Copied btmp2 contents as hex: 00, 00
Copied btmp2 as ushort (16bit) int: 0 [0]

Comment faire en sorte que la seconde partie (btmp2) se comporte de la même manière que la première partie (atmp2) ?

7voto

sdaau Points 6262

Il s'avère que, en utilisant split, cela crée effectivement un tableau avec les mêmes octets que dans la chaîne d'origine ; cependant, il semble également marquer d'une manière ou d'une autre le tableau résultant comme "textuel", ce qui fait échouer le traitement ultérieur avec "Argument non numérique".

La réponse est simplement de remplacer la ligne split par une qui utilise unpack, à la place :

- my @btmp = split('',$indata);
+ my @btmp = unpack('C*',$indata);

... et après cela, tout fonctionne comme prévu (les deux sorties sont identiques). De manière intéressante, dans les deux cas, "lastindex" (pour le tableau dérivé d'une chaîne) sera affiché comme 10 (ce qui m'a fait penser que quelque chose pouvait être incorrect avec binmode, c'est pourquoi toutes ces instructions sont là dans le code).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X