【问题标题】:Perl pack() function and "B" format character to PhpPerl pack() 函数和“B”格式字符到 Php
【发布时间】:2013-03-08 03:47:39
【问题描述】:

"B" 在来自 Perl 代码的 pack 语句中做了什么?

$hce_hash=pack('B*', $hce_hash);

PHP中有没有等价的函数?

【问题讨论】:

  • 问错地方了!
  • 正如您已经被告知的,此站点是您编写代码的地方,我们会在遇到问题时为您提供帮助。这个网站不是我们教你编程或为你翻译的地方。 stackoverflow.com/questions/15273113/perl-to-php-function
  • 如果您比较各自的文档(PerlPHP),您应该能够意识到并没有真正的等价物。然而,这是一个有趣的问题;如果有人想出一个解决方法会很好。

标签: php perl pack


【解决方案1】:

PHP 的pack 不支持B* 的格式,但它支持H*。在 Perl 中,您可以使用

sub pack_Bstar {
  my($bits) = @_;
  my $Hstar;

  my $nybble = 0;
  for (my $i = 0; $i < length $bits; ++$i) {
    $nybble *= 2;
    $nybble += int substr($bits, $i, 1);
    if ($i % 4 == 3) {
      $Hstar .= sprintf "%x", $nybble;
      $nybble = 0;
    }
  }

  my $pad = 4 - length($bits) % 4;
  if ($pad != 4) {
    $nybble = ($nybble << $pad);
    $Hstar .= sprintf "%x", $nybble;
  }

  pack "H*", $Hstar;
}

上面的代码不是惯用的 Perl,但翻译成 PHP 应该很简单。

H* 格式首先需要一个高 nybble(4 位)的十六进制字符串。上面的代码一次咀嚼四个位来计算每个 nybble 值。例如,对于1011的位串,追踪算法给出

  1. nybble = 0
  2. nybble = 2 * 0 + 1 = 1
  3. nybble = 2 * 1 + 0 = 2
  4. nybble = 2 * 2 + 1 = 5
  5. nybble = 2 * 5 + 1 = 11

10112确实是1110,也就是b16。如果最后一个 nybble 不完整(在 1 到 3 位之间),我们将该位左移适当的位数。这具有在右侧补零的效果。

测试:

my @tests = (
  ["01001010011101010111001101110100"                               => "Just"],
  ["0110000101101110011011110111010001101000011001010111001"        => "another"],
  ["01010000010010000101000000101111010100000110010101110010011011" => "PHP/Perl"],
  ["01101000011000010110001101101011011001010111001000101100"       => "hacker,"],
);

for (@tests) {
  my($input,$expect) = @$_;
  my $got = pack_Bstar $input;
  print "$input: ", ($got eq $expect ? "PASS" : "FAIL"), " ($got)\n";
}

输出:

01001010011101010111001101110100:通过(仅)
0110000101101110011011110111010001101000011001010111001:通过(另一个)
01010000010010000101000000101111010100000110010101110010011011:通过(PHP / Perl)
01101000011000010110001101101011011001010111001000101100:通过(黑客,)

【讨论】:

  • 这太低效了。如果语言没有将二进制转换为数字的方法,您应该为 0..15 创建一个位模式查找表
【解决方案2】:

pack 'B*', $s 返回由构成$s 中的字符串的01 字符组成的字符串所代表的字节。 $s 的值在必要时用零填充到可被 8 整除的长度。

例如,

pack 'B*', '0100101000110101'

结果

chr(0b01001010) . chr(0b00110101);

【讨论】:

    【解决方案3】:

    正如其他人所指出的,PHP 的 pack() 不支持 B 模板,该模板在 Perl 的 pack() 中将位串(表示为 01 字符的文字字符串)转换为压缩字节每字节 8 位的字符串。

    但是,由于 PHP 的 pack() 确实支持 H 模板,除了十六进制数字而不是位之外,它的功能相同,我们可以在 PHP 中模拟 Perl 的 B 模板,首先使用 base_convert() 来转换位转换成十六进制数字,然后打包:

    function pack_B( $bits, $len = false ) {
        // truncate input to desired length, if given:
        if ( $len === false ) $len = strlen( $bits );
        else $bits = substr( $bits, 0, $len );
    
        // pad input with zeros to next multiple of 4 above $len:
        $hexlen = (int)( ($len + 3) / 4 );
        $bits = str_pad( $bits, 4*$hexlen, "0" );
    
        // split input into chunks of 4 bits, convert each to hex and pack them:
        $nibbles = str_split( $bits, 4 );
        foreach ( $nibbles as $i => $nibble ) {
            $nibbles[$i] = base_convert( $nibble, 2, 16 );
        }
        return pack( "H*", implode( "", $nibbles ) );
    }
    

    (我们不能只将整个输入字符串提供给 base_convert() 的原因是它将中间结果存储为 PHP 浮点数,因此对于太大而无法准确表示的数字不会产生正确的结果浮点数。但是,一次做一个十六进制数字效果很好。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 2020-03-09
      • 1970-01-01
      • 2014-11-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多