perlhexprintfhuman-readable

perl print hexadecimal as human-readable


File forsojunk is as follows (with many more lines not shown).

    s/e\x27\x27\x27/é/g; 
    s/e\x27/é/g; 
    s/a\x5f/à/g; 

junk.pl is as follows.

#! /usr/bin/perl
use strict; use warnings;
while(<>) {
   $_ =~ s/s\x2f([^\x2f\x5c]+)([^\x2f]*)\x2f([^\x2f]*).*/1=$1; 2=$2; 3=$3/ ;
   print $1;
   print $2;
   print " -> ";
   print $3;
   print "\n";
}

which gives

> junk.pl forsojunk
e\x27\x27\x27 -> é
e\x27 -> é
a\x5f -> ò

but I do not want to print out the literal hex code such as \x27\x27\x27. I want to print out what it looks like, the readable form. At the first line, $2 should print out as ''' and the entire "message" in the first line should be

e''' -> é

How does one accomplish this?


Solution

  • You need to convert each 2-digit hexcode to a printable character.

    pack works, or using a loop with hex to convert from a base-16 string to a number, and then chr, printf, etc to convert to the corresponding character:

    #!/usr/bin/env perl
    use strict;
    use warnings;
    use open qw/IO :locale :std/;
    
    while(<>) {
        # Note the cleaned up regular expression
        if (my ($base, $rawaddons, $result) = m{s/([^/\\]+)([^/]*)/([^/]*)/}) {
            my @addons = split/\\x/, $rawaddons; # Split up the hexcodes and remove the \\x parts
            shift @addons; # Drop the first empty element
            print $base;
            # Any of the below ways work
            print pack('(H2)*', @addons);
            # printf '%c', hex for @addons;
            # print map { chr hex } @addons;
            print " -> $result\n";
        }
    }
    

    Example:

    $ perl junk.pl forsojunk
    e''' -> é
    e' -> é
    a_ -> à