darienhuss has asked for the wisdom of the Perl Monks concerning the following question:

Thanks to the monks who helped me with my previous problem, I'm ready to finally complete this project I've been working on, just one more problem to get past. Ok so here it goes:

I have these 8 character values stored in a list. Here are 2 examples: @list = 'a' '6' '5' '5' '4' '5' '0' 'e'. As you can see these are in hexadecimal. This is important. I need to be able to use these separate values to create another list, but this time it is a list of values of tuners (the hardware I'm running this perl script over carries 32 tuners, assigned 0-31.). before i do more explaining, these values are stored as string values. do I need to convert them to anything else before I can manipulate them as if they were hex?

more explaining needs to be done, so I'm going to do my best. each of those hex values corresponds to 4 different tuners, going backwards. the first value (a in the example) corresponds to tuners 31-28. the second value (6 in exmpl) 27-24. The third 23-20. 4th: 19-16. 5th: 15-12. 6th: 11-8. 7th: 7-4. 8th: 3-0. in each of those groups of tuners, they equal a value that will be added to the mask if they should be added to my list. the highest tuner is equal to an 8. the 2nd highest is equal to a 4. the third highest is equal to a 2, and the last is equal to a 1. So in the example, these tuners should be added to my list according to the first value (a): tuners 31 and 29. The second value is saying that tuners 26 and 25 should be turned on. The third is saying that tuners 20 and 21 should be added. The mask can change so the code needs to be able to account for that. I have no idea how to do this without at least a little bit of guidance and help. If I need to do some more explaining, then I will, just ask away.

In the end, the example should have stored in @tuner_list the tuners: 1,2,3,8,10,14,16,18,20,22,25,26,29,31.
  • Comment on using a hexadecimal mask to create a list of values (that the mask is pointing to)

Replies are listed 'Best First'.
Re: using a hexadecimal mask to create a list of values (that the mask is pointing to)
by almut (Canon) on Dec 18, 2008 at 15:58 UTC

    One way to do it:

    #!/usr/bin/perl my @list = ('a', '6', '5', '5', '4', '5', '0', 'e'); my $hex = join '', @list; my $bin = unpack("B*", pack("H*", $hex)); # "101001100101010101000101 +00001110" my $idx = -1; my @tuner_list = map {$idx++; $_ ? $idx : ()} reverse split //, $bin; print "@tuner_list\n"; # 1 2 3 8 10 14 16 18 20 22 25 26 29 31
Re: using a hexadecimal mask to create a list of values (that the mask is pointing to)
by BrowserUk (Patriarch) on Dec 18, 2008 at 16:08 UTC

    Step by step:

    my $input = 'a6.55.45.0e';; my( $hex = $input ) =~ tr[.][]d;; ## Remove dots;; my $revHex = reverse $hex;; my $packedInt = pack 'h*', $revHex;; my @tuners;; vec( $packedInt, $_, 1 ) and push @tuners, $_ for 0 .. 31;; print "@tuners";; 1 2 3 8 10 14 16 18 20 22 25 26 29 31

    Or as a compact sub:

    sub mask2list { ( my $hex = shift ) =~ tr[.][]d; my $packed = pack 'h*', scalar reverse $hex; map{ vec( $packed, $_, 1 )? $_ : () } 0 .. 31; } my @tuners = mask2list( 'a6.55.45.0e' ); print "@tuners"; 1 2 3 8 10 14 16 18 20 22 25 26 29 31

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: using a hexadecimal mask to create a list of values (that the mask is pointing to)
by moritz (Cardinal) on Dec 18, 2008 at 15:44 UTC
    So basically you want to translate each hex character to a bit mask, assemble the bit masks, reverse their order and then collect all indexes for which the bit is 1?

    I'm sure that pack and unpack can help you quite a bit, maybe together with vec.

    (And it might make it easier if you work with pair of hex characters instead of single characters, because a pair of hex chars is a byte, and that works nicer than a 4 bit nibble for many operations).

Re: using a hexadecimal mask to create a list of values (that the mask is pointing to)
by darienhuss (Initiate) on Dec 18, 2008 at 19:04 UTC
    heck yeah you guys are amazing! both solutions worked (almut and browserUK). at first I didn't think they did but I needed to throw in a chomp (because I'm not actually setting the initial hex mask, I'm receiving it from the piece of hardware via snmpget) and then it worked. thanks again! :)
Re: using a hexadecimal mask to create a list of values (that the mask is pointing to)
by kennethk (Abbot) on Dec 18, 2008 at 15:58 UTC

    Short answer: the hex function will convert your strings into hex numbers.

    @numbers = (); for (@list) { push @numbers, hex $_; }

    Perl has an internal representation of hex numbers, where each term starts with 0x, so your list would be

    @list = (0xA, 0x6, 0x5, 0x5, 0x4, 0x5, 0x0, 0xE)

    Note that simply concatenating a 0x to the front of your string will not work. As well, I played a bit with pack and unpack, and while in theory you can get similar functionality, I couldn't seem to get my expressions right.

    Update:Once you have your values in integer format, you can use the bit shift and mod operators to extract the info you actually care about

    my $value = 14; #Examine 3rd bit from the right print ($value >> 3) % 2;