Perl Pack解包和反向字节顺序

时间:2014-05-05 03:47:50

标签: perl unpack

我试图编写一个脚本来查找文本文件中的十六进制字符串,并将它们转换为反向字节顺序。我遇到的麻烦是一些十六进制字符串是16位而一些是64位。我使用Perl的包来打包和解包16位十六进制数字,这样可以正常工作,但64位不能。

print unpack("H*", (pack('I!', 0x20202032))). "\n"; #This works, gives 32202020
#This does not
print unpack("H*", (pack('I!', 0x4f423230313430343239303030636334))). "\n";

我用q和Q(我得到ffffffffffffffff)尝试了第二次。我接近这一切都错了吗?

作为背景知识,我有一个多GB的管道分隔文本文件,它具有反向字节顺序的十六进制字符串,如上所述。此外,文件的列不是标准的;有时十六进制字符串出现在一列中,有时出现在另一列中。我需要将十六进制字符串转换为它们的反向字节顺序。

2 个答案:

答案 0 :(得分:3)

始终use warnings;。如果您这样做,您将收到以下消息:

Integer overflow in hexadecimal number at scratch.pl line 8.
Hexadecimal number > 0xffffffff non-portable at scratch.pl line 8.

可以通过use bigint;并将您的第二个号码声明更改为hex('0x4f423230313430343239303030636334')来解决这些问题。

但是,这个数字仍然太大,pack 'I'无法处理。

也许这可以通过简单的字符串操作来完成:

use strict;
use warnings;

my @nums = qw(
    0x20202032
    0x4f423230313430343239303030636334
);

for (@nums) {
    my $rev = join '', reverse m/([[:xdigit:]]{2})/g;
    print "$_ -> 0x$rev\n"
}

__END__

输出:

0x20202032 -> 0x32202020
0x4f423230313430343239303030636334 -> 0x3463633030303932343034313032424f

或处理非偶数长度的数字:

my $rev = $_;
$rev =~ s{0x\K([[:xdigit:]]*)}{
    my $hex = $1;
    $hex = "0$hex" if length($hex) % 2;
    join '', reverse $hex =~ m/(..)/g;
}e;
print "$_ -> $rev\n"

答案 1 :(得分:1)

要迂腐,示例中的十六进制数字是32位和128位长,而不是16和64.如果最长的只有64位长,则可以成功使用Q { {1}}模板如你所愿(假设您的perl已被编译为支持64位整数)。

无论如何都可以使用pack / pack解决方案(如果添加了unpack - 您还必须从十六进制字符串中删除前导reverse或修剪结果中的最后两个字符):

0x

您的值示例:

print unpack "H*", reverse pack "H*", $hex_string;