【问题标题】:Pack/unpack binary string in Perl在 Perl 中打包/解包二进制字符串
【发布时间】:2014-06-09 15:37:43
【问题描述】:

我正在尝试理解一段 Perl 代码。我认为它的目的是从输入整数生成二进制字符串,但位顺序相反(左侧为低位,右侧为高位)。但是,我不明白打包/解包对输入值做了什么;它似乎是不正确的。

考虑这个测试代码:

for (my $i = 0; $i < 16; $i++) {

    for (my $j = 0; $j < 16; $j++) {

        $x = $i * 16 + $j;
        $x = unpack("b8", pack("U", $x));
        printf $x;
        print " ";
    }
    print "\n";
}

这会产生:

00000000 10000000 01000000 11000000 00100000 10100000 01100000 11100000 00010000 10010000 01010000 11010000 00110000 10110000 01110000 11110000
00001000 10001000 01001000 11001000 00101000 10101000 01101000 11101000 00011000 10011000 01011000 11011000 00111000 10111000 01111000 11111000
00000100 10000100 01000100 11000100 00100100 10100100 01100100 11100100 00010100 10010100 01010100 11010100 00110100 10110100 01110100 11110100
00001100 10001100 01001100 11001100 00101100 10101100 01101100 11101100 00011100 10011100 01011100 11011100 00111100 10111100 01111100 11111100
00000010 10000010 01000010 11000010 00100010 10100010 01100010 11100010 00010010 10010010 01010010 11010010 00110010 10110010 01110010 11110010
00001010 10001010 01001010 11001010 00101010 10101010 01101010 11101010 00011010 10011010 01011010 11011010 00111010 10111010 01111010 11111010
00000110 10000110 01000110 11000110 00100110 10100110 01100110 11100110 00010110 10010110 01010110 11010110 00110110 10110110 01110110 11110110
00001110 10001110 01001110 11001110 00101110 10101110 01101110 11101110 00011110 10011110 01011110 11011110 00111110 10111110 01111110 11111110
01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011
01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011
01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011
01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011 01000011
11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011
11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011
11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011
11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011 11000011

那么,这里发生了什么?似乎所有“高 ASCII”值(超过 128 个)都被错误地转换了,但是尽管阅读了 packunpack 的文档,但我看不到这里发生了什么。

【问题讨论】:

  • 这可能会有所帮助。 perldoc.perl.org/perlpacktut.html
  • 什么版本的 perl?我just tested this 无法复制结果。如果我不得不猜测,它是packU 格式,它返回一个可能是也可能不是是1字节的Unicode字符。超过 127 的值可以编码为 2 字节字符。
  • 是的,这看起来很合理,谢谢!

标签: perl pack unpack


【解决方案1】:

packU 模式将其打包成一个 UTF-8 字符,可能是也可能不是是一个字节。 (您的输出以 110 开头的事实意味着 the result is two bytes long,但这是另一回事。)

From the documentation:

U - A Unicode character number. Encodes to a character in character mode and UTF-8 (or UTF-EBCDIC in EBCDIC platforms) in byte mode.

您应该使用C 选项来确保您只得到一个字节:

C - An unsigned char (octet) value.

这给了我们:

for ( my $i = 0; $i < 16; $i++ ) {

    for ( my $j = 0; $j < 16; $j++ ) {

        $x = $i * 16 + $j;
        $x = unpack("b8", pack("C", $x));
        printf $x;
        print " ";
    }
    print "\n";
}

【讨论】:

  • 旁注:$x = unpack("b8", pack("C", $x)); 写成$x = reverse(sprintf("%08B", $x)); 可能会更清楚一些。位顺序反转很奇怪。如果你没有反转($x = unpack("B8", pack("C", $x));),你可以使用printf "%08B", $x;
  • 再次感谢。由于我将其转换为 C,因此对 swizzle 位的字符串操作将使用实际的位移运算符而不是将来的字符串操作来完成!我只需要了解它在做什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-15
  • 1970-01-01
  • 1970-01-01
  • 2011-09-19
  • 2017-04-16
  • 2012-05-07
  • 2022-01-09
相关资源
最近更新 更多