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

I am trying to append a non printable character (FileSeparator/FS/0x1c) onto an ascii string and then inspect the contents of the string for debugging purposes. I think I am screwed up on the "how to inspect the contents of an ASCII string in hex) side.

my $string = pack('a*','123456'); foreach (my $i=0; $i<length($string); $i++) { printf("%02x ", substr($ +string,$i,1)); } print "\n";
the result is: 01 02 03 04 05 06 the expectation was: 31 32 33 34 35 36 continuing, let's add the FS character to the string:
$string .= pack('a', 0x1c); foreach (my $i=0; $i<length($string); $i++) { printf("%02x ", substr($ +string,$i,1)); } print "\n";
the result is: 01 02 03 04 05 06 02 the expectation was: 31 32 33 34 35 36 1c (Further explanation: this is for use with serial communications of for sending into sockets) Thanks!!

Replies are listed 'Best First'.
Re: concatenate a non-printable character onto an ascii string and inspect the content
by choroba (Cardinal) on Sep 20, 2017 at 16:21 UTC
    What do you think pack 'a*', '123456' does? Are you interested in ord?
    #!/usr/bin/perl use warnings; use strict; my $string = '123456'; $string .= "\x1c"; # or chr 0x1c printf '%02x ', ord $_, ' ' for split //, $string; print "\n";
    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      Your first download worked very nicely. Thank you.

      So packing the ASCII string is wrong, It is stored as 0=0x30 etc. (see my own reply to my question). The trick was concatenating "\x1c"

      .
Re: concatenate a non-printable character onto an ascii string and inspect the content
by AnomalousMonk (Archbishop) on Sep 20, 2017 at 17:14 UTC

    You're running into the helpful inclination of Perl to freely interconvert strings and numbers in situations where it seems to make sense (and even sometimes where it doesn't). As | Similarly to what choroba said, what do you think  substr '123456', 0, 1 is?

    c:\@Work\Perl\monks>perl -wMstrict -le "use Data::Dump qw(dd); ;; my $string = pack('a*', '123456'); dd $string; ;; print substr $string, 0, 1; printf qq{%02x \n}, substr $string, 0, 1; printf qq{%02x \n}, '1'; ;; foreach my $c (unpack 'C*', $string) { printf '%02x ', $c; } print ''; ;; $string .= qq{\x1c}; dd $string; ;; foreach my $c (unpack 'C*', $string) { printf '%02x ', $c; } " 123456 1 01 01 31 32 33 34 35 36 "123456\34" 31 32 33 34 35 36 1c

    Update: Finally noticed that choroba didn't actually say anything about substr, but rather about pack. Still, I think the question about substr is valid.

Re: concatenate a non-printable character onto an ascii string and inspect the content
by kcott (Archbishop) on Sep 21, 2017 at 06:17 UTC

    G'day, holandes777,

    It looks like you've resolved this with ord.

    I don't know how you intend to use 0x1c in your real code; however, I thought I'd just point out that it's special to Perl inasmuch as it's the default value for the subscript separator ($;).

    $ perl -E 'say sprintf "%02x", ord $;' 1c

    It was used in Perl4 (and earlier) to emulate multidimensional arrays. It's not needed for that purpose in Perl5: follow the link I provided for more on that.

    As it's still part of the (Perl5) language, you should be aware of it; and avoid using it in a way such that it's interpreted as a subscript separator, which could result in a bug that's hard to track down. As an example, consider the following quick and dirty one-liner, which shows Data::Dump expanding the full key (e.g. 0\x1C0) but, when just printed, the (non-printable) 0x1c part is not displayed (e.g. 00).

    $ perl -E 'use Data::Dump; my (%h, $x); for my $i (0,1) { for my $j (0 +,1) { $h{$i,$j} = $x++ } } dd \%h; say for sort keys %h' { "0\x1C0" => 0, "0\x1C1" => 1, "1\x1C0" => 2, "1\x1C1" => 3 } 00 01 10 11

    — Ken

Re: concatenate a non-printable character onto an ascii string and inspect the content
by salva (Canon) on Sep 21, 2017 at 06:45 UTC
    You can also use Devel::Peek for inspecting the contents of any perl value:
    use Devel::Peek; Dump(pack('a*','123456') . pack('a', 0x1c)); Dump(pack('a*','123456') . pack('a', "\x1c"));
Re: concatenate a non-printable character onto an ascii string and inspect the content
by holandes777 (Scribe) on Sep 20, 2017 at 16:17 UTC
    Aha: ord seems to solve this:
    my $string = '123456'; foreach (my $i=0; $i<length($string); $i++) { printf("%02x ", ord(subs +tr($string,$i,1))); } print "\n";
    produces the expected: 31 32 33 34 35 36, but the 0x1c is still a mystery
Re: concatenate a non-printable character onto an ascii string and inspect the content
by BillKSmith (Monsignor) on Sep 23, 2017 at 14:42 UTC
    The function unpack can be your friend. See the first example in the tutorial perlpacktut
    #!perl #perlmonks node_id=1199762 use strict; use warnings; use charnames qw(:full); my $string = "123456\N{FS}"; $,=q( ); print unpack( '(H2)*', $string); OUTPUT: 31 32 33 34 35 36 1c
    Bill

      I upvoted your post for its pack-related links and  H example.

      However, there was one feature of the example that made my buggy-sense tingle: assignment to  $, to achieve desired output formatting. (I realize you may have done this merely to support a quick-and-dirty example, but I think it's a best-practice to always exemplify Best Practices in example code.)

      Of course,  $, is a Perl special variable (see perlvar). These variables are all package-globals, and as such should IMHO always be carefully local-ized within the narrowest possible scope when they are changed. E.g.:

      c:\@Work\Perl\monks>perl -le "use strict; use warnings; use charnames qw(:full); ;; my $string = qq{123456\N{FS}}; { local $, = q( ); print unpack '(H2)*', $string; } " 31 32 33 34 35 36 1c
      Even so, localized scoping is dynamic, not lexical, so such a change propagates to all subsidiary scopes, such as that in an invoked subroutine. This can lead to some very perplexing bugs.

      I think an even better practice is to format an output string (or do most other things) in a way that avoids scoping issues altogether:

      c:\@Work\Perl\monks>perl -le "use strict; use warnings; use charnames qw(:full); ;; my $string = qq{123456\N{FS}}; print join ' ', unpack '(H2)*', $string; " 31 32 33 34 35 36 1c
      join does just what you want and has absolutely no effect outside of the statement in which it appears. Control of scope gives you great power, but with great power comes great capability to blow your entire leg off!


      Give a man a fish:  <%-{-{-{-<