Perl:如何从一个字节中提取某些位然后将这些位转换为十六进制值?

时间:2012-11-24 16:39:53

标签: perl bitmap bit-manipulation bit text-parsing

我需要提取一个字节的某些位并将提取位转换回十六进制值。

示例(字节的值为0xD2):

76543210 bit position
11010010 is 0xD2
  • 位0-3定义通道0010b0x2
  • 位4-5定义控制器01b0x1
  • 位6-7定义端口11b0x3

我需要从字节0xD2到频道为0x2,控制器为0x1,端口为0x3

我用谷歌搜索分配并找到函数pack / unpackvecsprintf。但是我正在摸索如何使用这些功能实现这一目标。知道如何在Perl中实现这个目标吗?

2 个答案:

答案 0 :(得分:8)

初始格式是什么?

my $chr = chr(0b11010010);  # A character  e.g. from read()
my $bin = '11010010';       # Binary
my $hex = 'D2';             # Hexadecimal
my $num = 0b11010010;       # A number.
my $num = 0xD2;             # A number.

您想首先将其转换为数字

my $num = ord($chr);
my $num = unpack('C', $chr);  # Alternative
my $num = oct("0b$bin");
my $num = hex($hex);

然后你使用轮班和面具。

my $channel    = ($num >> 0) & 0xF;   # Or just: $num & 0xF
my $controller = ($num >> 4) & 0x3;
my $port       = ($num >> 6) & 0x3;   # Or just: $num >> 6

(您可以使用0b11110b110b11作为面具。大多数人都使用十六进制。)

或者让vec为你找出面具。

my $channel    = vec $num, 0, 4;
my $controller = vec $num, 4, 2;
my $port       = vec $num, 6, 2;

以下是$controller的示例:

  11010010
      >> 4
  --------
      11010010
&       11
  --------
        01

(为清楚起见省略了一些零。)

答案 1 :(得分:2)

vec是个不错的选择。我认为这非常简单:

#!/usr/bin/env perl

use strict;
use warnings;
use feature 'say';

my @channels    = map "channel_$_"      => 0 .. 15;
my @controllers = map "controller_$_"   => 0 .. 3;
my @ports       = map "port_$_"         => 0 .. 3;

my $bits        = 0b11010010;
my $channel     = vec $bits, 0, 4;
my $controller  = vec $bits, 4, 2;
my $port        = vec $bits, 6, 2;

say "channel    : $channels[$channel]";
say "controller : $controllers[$controller]";
say "port       : $ports[$port]";

输出:

channel    : channel_2
controller : controller_1
port       : port_3