How to tell apart numeric scalars and string scalars in Perl?

前端 未结 9 1429
一生所求
一生所求 2020-12-16 12:31

Perl usually converts numeric to string values and vice versa transparently. Yet there must be something which allows e.g. Data::Dumper to discriminate between

相关标签:
9条回答
  • 2020-12-16 12:42

    Based on your comment that this is to determine whether quoting is needed for an SQL statement, I would say that the correct solution is to use placeholders, which are described in the DBI documentation.

    As a rule, you should not interpolate variables directly in your query string.

    0 讨论(0)
  • 2020-12-16 12:43

    The autobox::universal module, which comes with autobox, provides a type function which can be used for this purpose:

    use autobox::universal qw(type);
    
    say type("42");  # STRING
    say type(42);    # INTEGER
    say type(42.0);  # FLOAT 
    say type(undef); # UNDEF 
    
    0 讨论(0)
  • 2020-12-16 12:45

    I don't think there is perl function to find type of value. One can find type of DS(scalar,array,hash). Can use regex to find type of value.

    0 讨论(0)
  • 2020-12-16 12:46

    A scalar has a number of different fields. When using Perl 5.8 or higher, Data::Dumper inspects if there's anything in the IV (integer value) field. Specifically, it uses something similar to the following:

    use B qw( svref_2object SVf_IOK );
    
    sub create_data_dumper_literal {
        my ($x) = @_;  # This copying is important as it "resolves" magic.
        return "undef" if !defined($x);
    
        my $sv = svref_2object(\$x);
        my $iok = $sv->FLAGS & SVf_IOK;
        return "$x" if $iok;
    
        $x =~ s/(['\\])/\\$1/g;
        return "'$x'";
    }
    

    You could use similar tricks. But keep in mind,

    • It'll be very hard to stringify floating point numbers without loss. (Floating pointer numbers are identified using $sv->FLAGS & SVf_NOK.)

    • You need to properly escape certain bytes (e.g. NUL) in string literals.

    • A scalar can have more than one value stored in it. For example, !!0 contains a string (the empty string), a floating point number (0) and a signed integer (0). As you can see, the different values aren't even always equivalent. For a more dramatic example, check out the following:

      $ perl -E'open($fh, "non-existent"); say 0+$!; say "".$!;'
      2
      No such file or directory
      
    0 讨论(0)
  • 2020-12-16 12:49

    It is more complicated. Perl changes the internal representation of a variable depending on the context the variable is used in:

    perl -MDevel::Peek -e '
        $x = 1;    print Dump $x;
        $x eq "a"; print Dump $x;
        $x .= q(); print Dump $x;
    '
    SV = IV(0x794c68) at 0x794c78
      REFCNT = 1
      FLAGS = (IOK,pIOK)
      IV = 1
    SV = PVIV(0x7800b8) at 0x794c78
      REFCNT = 1
      FLAGS = (IOK,POK,pIOK,pPOK)
      IV = 1
      PV = 0x785320 "1"\0
      CUR = 1
      LEN = 16
    SV = PVIV(0x7800b8) at 0x794c78
      REFCNT = 1
      FLAGS = (POK,pPOK)
      IV = 1
      PV = 0x785320 "1"\0
      CUR = 1
      LEN = 16
    
    0 讨论(0)
  • 2020-12-16 12:52

    There's no way to find this out using pure perl. Data::Dumper uses a C library to achieve it. If forced to use Perl it doesn't discriminate strings from numbers if they look like decimal numbers.

    use Data::Dumper;
    $Data::Dumper::Useperl = 1;
    print Dumper(['1',1])."\n";
    
    #output
    $VAR1 = [
              1,
              1
            ];
    
    0 讨论(0)
提交回复
热议问题