Re: How can I test for the representation of an integer?
by Eily (Monsignor) on Apr 25, 2016 at 10:04 UTC
|
This answer on stackoverflow seems to do what you want (based on the fact that the bitwise & operator has a different output depending on the type of the scalar) with pure perl. I suppose there is a XS module somewhere that lets you know precisely what there is inside the SV.
But as stated in the above post, the fact that a variable has a numerical value does not only depend on its declaration, but also on whether or not it was ever used in numerical context:
perl -MData::Dumper -E '@a = (1, "1", 1, "1", "1o"); say "$a[2]"; say
+$a[4]+$a[3]; say Dumper \@a'
1
2
$VAR1 = [
1,
'1',
1,
1,
'1o'
];
Edit: added "output" in my parenthesis, because why would I write all the words on the first try? | [reply] [d/l] |
Re: How can I test for the representation of an integer?
by clueless newbie (Deacon) on Apr 25, 2016 at 11:22 UTC
|
Thanks to Autobox you can do
use autobox::universal qw(type);
say type("42"); # STRING
say type(42); # INTEGER
say type(42.0); # FLOAT
say type(undef); # UNDEF
See chocolateboy's response in "How to tell apart numeric scalars and string scalars in Perl?"
| [reply] [d/l] |
|
Thanks - that's probably the most accessible way I've seen.
Feels like it should be in Scalar::Util.
| [reply] |
|
Feels like it should be in Scalar::Util
I don't think I would trust Scalar::Util to not fiddle about with the wrapping.
For example, Scalar::Util's looks_like_number() returns true for a Math::BigInt object, even though the looks_like_number() XS function would return false.
Cheers, Rob
| [reply] |
|
Thank you, very useful!
I ended up with this:
if (eval {require autobox::universal;}) {
autobox::universal->import('type');
} else {
print 'Warning: Cannot locate autobox/universal.pm in @INC (you may
+ need to install autobox)' . "\n" .
"In Strawberry Perl you can get autobox like this:\n" .
" 1. from a Windows Administrator (elevated) command prompt
+...\n" .
" 2. cd \\strawberry\\perl\\bin\n" .
" 3. cpan autobox::universal\n\n";
eval("sub type { return '?';}");
}
| [reply] [d/l] |
Re: How can I test for the representation of an integer?
by haukex (Bishop) on Apr 25, 2016 at 10:07 UTC
|
Hi sm@sh,
I don't know much about the internals, but from what I do know I'd guess it might be looking at the POK/IOK flags:
$ perl -MDevel::Peek -e 'Dump(1); Dump("1")';
SV = IV(0x21490e8) at 0x21490f8
REFCNT = 1
FLAGS = (IOK,READONLY,PROTECT,pIOK)
IV = 1
SV = PV(0x2129fa0) at 0x2149168
REFCNT = 1
FLAGS = (POK,IsCOW,READONLY,PROTECT,pPOK)
PV = 0x218fef0 "1"\0
CUR = 1
LEN = 10
COW_REFCNT = 0
$ perl -MDevel::Peek -e '$a=42; $a="Hello"; Dump($a)';
SV = PVIV(0x83d2e0) at 0x8321f0
REFCNT = 1
FLAGS = (POK,IsCOW,pPOK)
IV = 42
PV = 0x834920 "Hello"\0
CUR = 5
LEN = 10
COW_REFCNT = 1
However, the much bigger question on my mind is why you need to know this? Perl "casts" between strings and numbers transparently, except for the case where a string can't be converted to a number, which you can determine beforehand with Scalar::Util's looks_like_number. Are you writing code that needs to peek behind the curtains more than that?
Regards, -- Hauke D | [reply] [d/l] [select] |
|
~$ perl -MData::Dumper -e 'print Dumper("1" =~ /1/)'
$VAR1 = 1;
~$ perl -MData::Dumper -e 'print Dumper("1" =~ /(1)/)'
$VAR1 = '1';
| [reply] [d/l] |
|
$ perl -MData::Dumper -e 'print Dumper("2" =~ /2/);'
$VAR1 = 1;
$ perl -MData::Dumper -e 'print Dumper("2" =~ /(2)/);'
$VAR1 = '2';
| [reply] [d/l] |
|
|
|
|
"1" =~ /1/;
print @->1?"yes\n":"no\n";
"1" =~ /(1)/;
print @->1?"yes\n":"no\n";
__END__
no
yes
This uses the special variable @-, aka @LAST_MATCH_START.
Update 2018-09-01: Actually, @+ will give you the number of capture groups! See my reply below for the difference.
Regards, -- Hauke D | [reply] [d/l] |
|
|
|
|
Re: How can I test for the representation of an integer?
by syphilis (Bishop) on Apr 25, 2016 at 12:31 UTC
|
If I want to know whether a value is an integer value (IV) or not (as often happens), I just use the the XS function SvIOK().
If it returns true then it's an IV, otherwise it's something else.
#!perl -l
use strict;
use warnings;
use Math::BigInt;
use Inline C => Config =>
BUILD_NOISY => 1;
use Inline C => <<'EOC';
int is_IV(SV * x) {
if(SvIOK(x)) return 1;
return 0;
}
EOC
my $x = '42';
print is_IV($x); # 0
$x += 0;
print is_IV($x); # 1
print is_IV(~0); # 1 (also UV)
print is_IV('?'); # 0;
my $mbi = Math::BigInt->new(1);
print is_IV($mbi); # 0;
print is_IV(2 ** 20); # 0 (NV)
Cheers, Rob | [reply] [d/l] |
|
Thanks - that answers my question perfectly.
| [reply] |
Re: How can I test for the representation of an integer?
by Discipulus (Abbot) on Apr 25, 2016 at 12:57 UTC
|
perl -MData::Dumper -E "say for Dumper([ 1, '1' ]),eval qq(1+'1'), len
+gth qq(1....).1;"
$VAR1 = [
1,
'1'
];
2
6
L*
There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
| [reply] [d/l] [select] |
Re: How can I test for the representation of an integer?
by Anonymous Monk on Apr 25, 2016 at 12:54 UTC
|
#!/usr/bin/perl
use strict;
use warnings;
use Scalar::Util qw(looks_like_number);
my @list = qw(1 "1" "1o");
foreach my $foo (@list) {
if( looks_like_number( $foo ) ) {
print "number\n";
}else{
print "string\n";
}
}
Just use looks_like_number from Scalar::Util
| [reply] [d/l] |
|
use Scalar::Util qw(looks_like_number);;
[0] Perl> print looks_like_number( $_ ) for 1, '1', 1.0, '1.0', '1o';;
4352
1
8704
5
0
But the OP wants to distinguish between 1 stored internally as an integer; and '1' stored internally as a string.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |