将存储为字符串的字节转换为Perl中的位并修改它

时间:2018-06-19 06:46:10

标签: perl binary hex

我正在尝试使用Perl脚本执行以下操作:

  • 从存储为字符串的十六进制数中提取两个字符 - >这将给出一个写为字符串
  • 的字节
  • 将此字节转换为二进制(如果存在则必须保留前导零)
  • 更改二进制文件中的特定位
  • 转换回十六进制
  • 替换为原始十六进制数

为此,经过长时间的互联网研究,我提出了以下几点:

# Initialize my variable: in my function, this is passed as input
$str = '5B CD 02 01 10';

# Extract the two characters to form a Byte
$OldByte_str = substr($str,0,2); 

# Convert to binary. Supposed to give '0101 1011'
$PDM_OldBits =  ( "Binary: %b\n", $PDM_OldByte );

# Replace two bits.Supposed to give '01**10** 1011'
substr($PDM_OldBit,2,2)= '10';

# Convert back to Bytes. Supposed to give'6B'
$NewByte_str= sprintf("0x%x", stringdecimal(arraystring($PDM_OldBits))); 

# Substitute back into the original Bytes string.
# Supposed to give: '**6B** CD 02 01 10'
substr($str,0,2)= $PDM_NewByte;

使用:

sub stringdecimal {
    return unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
}

sub arraystring {
    my $string = join('', @_);
    return $string;
}

但是,没有进行二进制转换;因此我也无法检查其余的代码。

作为Perl的初学者,我在这里提出这个问题 - 以防有人对我的问题有一些提示或解决方案。

2 个答案:

答案 0 :(得分:2)

错误输入时,

strictwarnings会一直给你提示。

use strict;
use warnings;

sub stringdecimal {
    # return unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
    return oct("0b" . shift);
}

my $str = '5B CD 02 01 10';   #Initialize my variable:in my function, this is passed as input
my $OldByte_str = substr($str,0,2); #extract the two characters to form a Byte

my $PDM_OldBits =  sprintf( "%b", hex($OldByte_str) );#Convert to binary. Supposed to give '0101 1011'

substr($PDM_OldBits,1,2)= '10';  #Replace two bits.Supposed to give '01**10** 1011'

my $NewByte_str= sprintf("%X", stringdecimal($PDM_OldBits)); #Convert back to Bytes. Supposed to give'6B'

substr($str,0,2)= $NewByte_str; #Substitute back into the original Bytes string.Supposed to give: '**6B** CD 02 01 10'

print $str, "\n";

答案 1 :(得分:2)

以下是另一种解决方案 - 仅使用pack()unpack()以及一次调用substr()(无sprintf())。它将修改数组中的每个值。 (如果您不想,只需取出for()循环并将$_替换为$bytes[0]。)

use strict;
use warnings;
use feature('say');

my $str = '5B CD 02 01 10';

my ($orig, $bits, $hex);
my @bytes = split(/ /, $str);
for (@bytes) {
    $bits = unpack('B8', chr(hex($_)));
    $orig = $bits; # for 'debugging'
    substr($bits, 2, 2) = '10';
    say $orig . ' -> ' . $bits;
    $hex = unpack('H2', pack('B8', $bits));
    say $_ . ' -> ' . uc($hex);
}

输出......

01011011 -> 01101011
5B -> 6b
11001101 -> 11101101
CD -> ed
00000010 -> 00100010
02 -> 22
00000001 -> 00100001
01 -> 21
00010000 -> 00100000
10 -> 20

使用substr($str, 0, 2);提取感兴趣的字节 - 除了笨重之外 - 可能不可靠。例如,如果输入中的白色间距不一致,则可以提取'B '而不是'5B'' C'而不是'CD'。这就是我使用split()将字符串拆分为字节的原因。