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

Hi,

I'm trying to crack this problem from a while now, but do not seem to find a way through it. I'm sure something obvious is being missed. I was asked to take a shot at this while requesting review on an earlier post here: Re^4: add missing elements and remove duplicates....and some more questions..

I am not looking for a direct answer though, I just need some pointers.

I have an array like this:
my @arr= qw (10 10 20 0x47 1 30 45 45);

I am trying to convert it to an array with numbers,but the quotes seem to cause problems. So I tried this:

use strict; use warnings; use v5.10.1; my @arr= qw (10 10 20 0x47 1 30 45 45); my @converted = grep $_ !~ /'/, @arr; foreach my $element (@converted) { my $num = sprintf "%d", $element; print "$num\n"; }

But I still get this:

10 10 20 Argument "0x47" isn't numeric in sprintf at num.pl line 8. 0 1 30 45 45

However, if I just try the hex number by itself, that seems to work:

use strict; use warnings; use v5.10.1; my $hexnum = sprintf ("%d", 0x47); print "$hexnum\n";

The above prints 71 which is the decimal for hex 0x47. What am I missing here? Please help.

Thinkpad T430 with Ubuntu 16.04.2 running perl 5.24.1 thanks to plenv!!

Replies are listed 'Best First'.
Re: Converting quoted strings to numbers in array
by choroba (Cardinal) on Apr 23, 2017 at 20:49 UTC
    For Perl, strings and numbers are different, even if it's easy to convert between them. A string can be specified in quotes, e.g.
    'string' "another string" q(yet another) qq<or like this>

    etc. Numbers can be specified in different ways, too:

    12 1_2 0b1100 0x0c

    All of them are just different ways how to represent the number 12. The problem is that 0x0c as a string , i.e. in quotes, is not interpreted as a number, but as a string. To convert it to a number, you need to use the oct function:

    #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; my @arr = qw( 10 10 20 0x47 1 30 45 45 ); my @converted = map /^0x/ && oct || $_, @arr; say for @converted;

    ($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,

      Hi Choroba,

      Thank you for replying. Please let me know if there is a reason to use a oct function for a hex string?

      Thinkpad T430 with Ubuntu 16.04.2 running perl 5.24.1 thanks to plenv!!

        If you were dealing with a mixture of binary (as 0b...), hexadecimal (as 0x...), and octal strings, e.g. in a loop, then oct would be useful.

        When you know it's a hexadecimal string (e.g. /^0x/ && ...), I'd use the hex function. It makes your intent clear and obvious and, in my opinion, the code is far more readable.

        The actual result is the same whichever you use:

        $ perl -E 'say oct "0x47"; say hex "0x47"' 71 71

        And just a word of warning, /^0x/ may not do what you want:

        $ perl -E 'say "0x47_not_hex" =~ /^0x/ ? "is hex" : "is NOT hex"' is hex $ perl -E 'say "0x47_not_hex" =~ /^0x[0-9a-fA-F]+$/ ? "is hex" : "is N +OT hex"' is NOT hex

        — Ken

        The word oct in my reply was a link. Have you clicked it and read the documentation?

        > If EXPR happens to start off with 0x , interprets it as a hex string.

        Maybe not the best name for such a function, but that's how it is.

        ($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,
Re: Converting quoted strings to numbers in array
by AnomalousMonk (Archbishop) on Apr 23, 2017 at 22:39 UTC

    After you've finished the problem you've set youself in the OP, consider what it would take to be able to freely intermix literal numbers and quoted numbers of any (supported) base:
        123, '123', 0123, '0123', 0x123, '0x123', 0b1101, '0b1101'
    (Hint: try some simple experimentation with oct; be sure to read its documentation thoroughly.)

    Then also support negative and positive intermixed literal/quoted numbers:
        -123, '-123', -0123, '-0123', -0x123, '-0x123', -0b1101, '-0b1101'


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

Re: Converting quoted strings to numbers in array
by Marshall (Canon) on Apr 24, 2017 at 05:48 UTC
    The "qw" means quote word(s). This is aide to help in typing in lots of strings. That's all it does.

    If you want to mix decimal,octal,hex numbers in some @a=qw(...),see below. Just ask Perl to evaluate what that string means in terms of an actual "number".

    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @array_of_strings = qw (10 20 0x47 1 30 0b011); # # "qw" is "quote word(s), this is the same as: # my @array_of_strings = ("10","20","0x47","1","30","0b011"); print Dumper \@array_of_strings; # only string context not "numbers" my @array = map{eval $_}@array_of_strings; # or my @array = map{eval $_} qw (10 20 0x47 1 30 0b011); print Dumper \@array; __END__ prints: $VAR1 = [ '10', '20', '0x47', '1', '30', '0b011' ]; $VAR1 = [ 10, 20, 71, 1, 30, 3 ];
    Update: added a binary number to example.
Re: Converting quoted strings to numbers in array
by Anonymous Monk on Apr 23, 2017 at 21:17 UTC
    my @arr = ( 1, 2, 3, 0x47 ); are numeric literals, see Scalar value constructors. In the source code they can look like 12345 or 4_294_967_296 or 0xff or 0377 or 0b011011 and will all be converted to numbers and stored as numbers. my @arr = qw/ 1 2 3 0x47 /; are strings, see qw//, it's the same as writing my @arr = ( "1", "2", "3", "0x47" );. In the source code, 0x47 is different from "0x47", the first one means 71 and the second one is a string with four characters. Strings will only be automatically converted to numbers if they are plain integers. If you want to know if a string will automatically convert to a number, you can use looks_like_number from Scalar::Util. "0x47" is not a plain integer, it's got an x character. Use oct to convert that string to a number, oct it does octal, 0x123 and 0b101 formats, or use hex which only does hexadecimal.
      Strings will only be automatically converted to numbers if they are plain integers.

      Or decimals, or scientific notation, or "Inf". But not hex or 12_34 notation, or 0b..., and octal numbers (0123 == 83) won't be recognized as such ("0123" == 123).

Re: Converting quoted strings to numbers in array
by pritesh_ugrankar (Monk) on Apr 24, 2017 at 12:45 UTC

    Hi,

    Thank you for taking time to reply to my query. Using the suggestions here, I have come up with the following solution.

    use strict; use warnings; my @arr = qw(10 20 0b1101 0xF 023); my @converted = map {$_ =~ /^0/ ? oct($_) : $_ } @arr; print "@arr\n"; print "@converted\n";

    The output seems satisfactory:

    C:\>perl practice.pl 10 20 0b1101 0xF 023 10 20 13 15 19

    I'm not sure if using a ternary operator inside map is considered un idiomatic, but it seems to work.

    Thank you all, thank you very much. This I know would seem trivial to you, but it's fixing something I've been fighting in my head from a while.

    Thinkpad T430 with Ubuntu 16.04.2 running perl 5.24.1 thanks to plenv!!
      I'm not sure if using a ternary operator inside map is considered un idiomatic, but it seems to work.

      I'd say it's idiomatic, and can even be shortened since $_ is used as the default argument for many functions (including oct) and for regexes that aren't bound to something via =~:

      use Data::Dump; my @arr = qw/ 10 20 0b1101 0xF 023 /; dd @arr; my @converted = map {/^0/ ? oct : $_} @arr; dd @converted; __END__ (10, 20, "0b1101", "0xF", "023") (10, 20, 13, 15, 19)
Re: Converting quoted strings to numbers in array
by Anonymous Monk on Apr 24, 2017 at 17:08 UTC
    For your consideration:
    use Data::Dumper; use Number::Convert; my @arr = map Number::Convert->new($_), (10, 20, 0b010101, 0xF, 023); print $_->ToDecimal, $/ for @arr;