Perl:如何将整数数组转换为一个字节

时间:2016-10-27 11:26:29

标签: perl

my @array= 0xffffffffffffffdf,0x2347,0x2360,0x2365,0xffffffffffffffcf,0x00,0x4a

我有一个1字节,2字节和8字节数据的数组。 数组中的2和8字节数据将随机出现

  1. 我想将2个字节的数组分成1个字节的每个字节,例如(0x2347 ---> 0x23,0x47

  2. 我想将8字节的有符号数据截断为1字节,例如{0xffffffffffffffcf ---> 0xcf

  3. my_code:

      use strict;
      use warnings;      
      my@array="0xffffffffffffffdf,0x2347,0x2360,0x2365,
                 0xffffffffffffffcf,0x00,0x4a";
      my @split_array;
      my @new_array;
      foreach my $index (@array) 
      {
      my @split_array;
    
      if (length $index >4) 
      {
    
        @split_array = map "0x$_", $index =~ /../g;
      } 
      elsif (length $index>16) 
      {     
       @split_array = map "0x$_", $index =~ /../g;       
      }
      else 
      {
        @split_array = $index;
      }
      @new_array=join(", ", @split_array);
      }
      print "@new_array\n";
    

    我的代码输出:

    0x0x,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0x,0,0xx2,0x34,0x7 ,, 0x0x,0x23,0x60,0x,0,0xx2,0x36,0x5 ,, 0x0x ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0x,0,0xx0,0x0,0x0x,0x4a 0x0x,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf

    预期产出:

    0xdf,0x23,0x47,0x23,0x60,0x23,0x65,0xcf,0x00,0x4a
    

    请建议我解释一下步骤..?

4 个答案:

答案 0 :(得分:2)

您希望-33(0xffffffffffffffdf)成为df(它的字节存储为带符号的8位整数)。

您希望9031(0x2347)成为23 47(它的字节存储为big-endian无符号16位整数)。

因此,除了值之外,您还需要提供应转换值的类型(例如Uint16)。 您缺少这些必要的信息。

其他两个答案试图通过猜测类型来解决这个问题,将小于256的值转换为单个输出字节。但是,您的小组之前提供的data表明"0x02"可能需要转换为0x00,0x02 0x02

因此,正如您的一位队友之前已经told,您无法从您提供的信息中获得所需的结果。例如,要获得输出渴望,你需要

my @data = (
    [ 'Sint8',  '0xffffffffffffffdf' ],
    [ 'Uint16', '0x2347' ],
    [ 'Uint16', '0x2360' ],
    [ 'Uint16', '0x2365' ],
    [ 'Sint8',  '0xffffffffffffffcf' ],
    [ 'Sint8',  '0x00' ],
    [ 'Sint8',  '0x4a' ],
);

完成后,您可以使用之前发布的solution

use strict;
use warnings;
no warnings qw( portable );
use feature qw( say );

my %packers = (
   Uint8  => sub { pack 'C*',  @_ },
   Sint8  => sub { pack 'c*',  @_ },
   Uint16 => sub { pack 'S>*', @_ },
   Sint16 => sub { pack 's>*', @_ },
   Uint32 => sub { pack 'L>*', @_ },
   Sint32 => sub { pack 'l>*', @_ },
);

my $packed = '';
for (@data) {
   my ($type, $hex) = @$_;

   # Convert to number (and fix sign).
   my $val = unpack 'q', pack 'q', hex $hex;

   my $packer = $packers{$type}
      or die("Unsupported type \"$type\"\n");

   $packed .= $packer->($val);
}

say
   join ',',
      map { sprintf("0x%02x", $_) }
         unpack 'C*',
            $packed;

输出:(完全符合预期)

0xdf,0x23,0x47,0x23,0x60,0x23,0x65,0xcf,0x00,0x4a

答案 1 :(得分:1)

你的程序有很多错误

每次更改时,您应至少LazyDataModel print的值

以下是一些观察

  • 在请求帮助之前,请至少整理并缩进代码。抛弃这样的东西并要求修复

  • 是不礼貌的
  • 您的$index(除了有可怕名称 - @array已经说过它是一个数组,因此@部分毫无价值)只包含一个元素,这是一个82个字符的字符串,中间有换行符和空格

  • 使用执行一次的array循环将该字符串分配给变量for(同样,一个可怕的名称 - 数组索引是从零开始的整数)

  • 首先测试字符串的长度是否为> 4.此测试将始终首先成功,即使是超过16个字符的字符串也应该由第二个测试处理。请记住,你有一个字符串,长度为82个字符

  • 请注意,即使您设法将$index设置为$index,也会将其字符串化为类似0xffffffffffffffdf的内容,如果您只是将每对字符视为十六进制数字

答案 2 :(得分:0)

map {($_ & 0xffffffffffff0000) ? ($_ & 0xff) : (($_ & 0xff00) >> 8, ($_ & 0xff))} @array;

map是迭代数组的关键字。它允许产生更多的项目作为输出而不是输入。

为了识别2字节数据中的8字节数据,我使用了一个掩码。如果位设置在低16位之外,则表示它是8字节数据。

为了分割两个字节的数据,我也使用了掩码。

答案 3 :(得分:0)

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

my @input_hex = (0xffffffffffffffdf,0x2347,0x2360,0x2365,
                 0xffffffffffffffcf,0x00,0x4a);

my @output_hex;

for (@input_hex) {
  if ($_ > 0xffff) {
    push @output_hex, ($_ & 0xff);
  } elsif ($_ > 0xff) {
    push @output_hex, ($_ & 0xff00) >> 8, ($_ & 0xff);
  } else {
    push @output_hex, $_;
  }
}

say join ',', map { sprintf '0x%02x', $_ } @output_hex;

在你解释你的问题时,我会尽可能多地努力解释我的答案 - 即没有。