halecommarachel has asked for the wisdom of the Perl Monks concerning the following question:
Hi Monks,
I have a data structure that I'm converting to a json string, which I then write to a file. The json file is used for a database. To convert the strings containing only digits to numbers, I add zero and then store in the structure. For some reason, when I look at the json file, some strings that were supposed to be converted to integers are still strings. Is there any way to guarantee a string is converted to a integer?
Thanks!
So a data dump looks good:
'cl_ip' => 209889,
But there's a string in the json file for this key:
"cl_ip":"209889"
Re: String to Integer, for json file
by davido (Cardinal) on Dec 12, 2013 at 05:39 UTC
|
JSON is more strongly typed than Perl. Perl (the language) is designed to not really make a strong distinction between an integer and a string. But internally there is a distinction. The "SV" entity that comprises a Perl scalar variable may have an "IV" (integer value) stored in it, or a "PV" (pointer to a string), or both (as well as a few other things). Perl mostly silently vivifies PV's and IV's within scalars as needed. So if you start with $var = 100;, that scalar variable holds just an IV. Now if you say print "$var\n";, $var goes through a stringification process that results in a PV being created within the scalar too. This is all taking place hidden behind the black box of Perl's internals, and in most circumstances this implementation detail is not relevant or even noticed.
However, JSON is typed, and JSON encoders have to decide whether a scalar contains an integer or a string. Most of the time the way they decide is by looking inside the variable to see if there is a PV. Remember, scalars may contain both. But the existence of an IV is overruled by the existence of a PV.
So you have to be very careful that this variable you're encoding has never been treated as a string. Or that a new variable is used: my $new_var = 0 + $var;.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Thank you davido for the explanation, it has truly enlightened me.
| [reply] [Watch: Dir/Any] |
|
A string can become a number again :) Its the flags that reveal the true nature (last touch)
use JSON qw/ to_json from_json /;
use Devel::Peek qw/ Dump /;
my $q = 3;
print "$q\n";
Dump( $q );
$q++;
Dump( $q );
print to_json( { a => 3, qw/ b 3 q/, $q } );
__END__
3
SV = PVIV(0x9a3778) at 0x99b524
REFCNT = 1
FLAGS = (PADMY,IOK,POK,pIOK,pPOK)
IV = 3
PV = 0xad23fc "3"\0
CUR = 1
LEN = 12
SV = PVIV(0x9a3778) at 0x99b524
REFCNT = 1
FLAGS = (PADMY,IOK,pIOK)
IV = 4
PV = 0xad23fc "3"\0
CUR = 1
LEN = 12
{"a":3,"q":4,"b":"3"}
http://search.cpan.org/dist/illguts/index.html | [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
Re: String to Integer, for json file
by karlgoethebier (Abbot) on Dec 12, 2013 at 08:51 UTC
|
use JSON::XS;
use Data::Dumper;
my %hash = ( cl_ip => 209890 );
my $json = encode_json \%hash;
print Dumper( \%hash );
print qq($json\n);
__END__
$VAR1 = {
'cl_ip' => 209890
};
{"cl_ip":209890}
Update:
I worry a bit about this. The OP wrote:
"...some strings that were supposed to be converted to integers are still strings...So a data dump looks good: 'cl_ip' => 209889, But there's a string in the json file for this key: "cl_ip":"209889"..."
From the JSON::XS manual:
"...Its primary goal is to be correct..."
The OP expects that the value of cl_ip is an integer after encoding, right?
In my example using JSON::XS the OP gets what he wants (integer).
IMHO JSON::XS works as designed - the result is what the OP expected.
If i still miss something: thanks for any advice.
I hope i didn't miss something. Regards Karl
«The Crux of the Biscuit is the Apostrophe»
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
use JSON qw/ to_json from_json /;
use Devel::Peek qw/ Dump /;
my $q = 3;
print "$q\n";
Dump( $q );
print to_json( { a => 3, qw/ b 3 q/, $q } );
__END__
3
SV = PVIV(0x9a3778) at 0x99b524
REFCNT = 1
FLAGS = (PADMY,IOK,POK,pIOK,pPOK)
IV = 3
PV = 0xad23bc "3"\0
CUR = 1
LEN = 12
{"a":3,"q":"3","b":"3"}
"a" gets 3 the number, b gets 3 the string , q becomes the 3 string
| [reply] [Watch: Dir/Any] |
|
my %hash;
$hash{'cl_ip'} = "29988" + 0;
I think the value is treated as a string at some point, perhaps when I search and replace any non-digit character.
Thanks, Rachel | [reply] [Watch: Dir/Any] [d/l] |
|
karls-mac-mini:monks karl$ perl -MData::Dumper -e '$hash{'cl_ip'} = "2
+9988" + 0;print Dumper(\%hash);'$VAR1 = {
'cl_ip' => 29988
};
But: so what ;-)
Update:
D'oh! Mille Regretz!
#!/usr/bin/env perl
+
use JSON::XS;
use Data::Dumper;
my %hash = ( cl_ip => 209890 );
my $json = encode_json \%hash;
print Dumper( \%hash );
print qq($json\n);
$hash{ cl_ip } += 0;
$json = encode_json \%hash;
print Dumper( \%hash );
print qq($json\n);
__END__
karl-mac-mini:monks karl$ ./json.pl
+
$VAR1 = {
+
'cl_ip' => 209890
+
};
+
{"cl_ip":209890}
+
$VAR1 = {
+
'cl_ip' => 209890
+
};
+
{"cl_ip":209890}
Update2:
#!/usr/bin/env perl
+
use JSON::XS;
use Data::Dumper;
my %hash = ( cl_ip => 209890 );
my $json = encode_json \%hash;
print Dumper( \%hash );
print qq($json\n);
$hash{ cl_ip } += 0;
$json = encode_json \%hash;
print Dumper( \%hash );
print qq($json\n);
$hash{ cl_ip } = "209890";
$json = encode_json \%hash;
print Dumper( \%hash );
print qq($json\n);
__END__
$VAR1 = {
'cl_ip' => 209890
};
{"cl_ip":209890}
$VAR1 = {
'cl_ip' => 209890
};
{"cl_ip":209890}
$VAR1 = {
'cl_ip' => '209890'
};
{"cl_ip":"209890"}
I'll give it up for tonight before i produce more shit...
Update3:
I'll give it up...
I don't:
#!/usr/bin/env perl
use JSON::XS;
use Data::Dumper;
use strict;
use warnings;
my %hash = ( cl_ip => 209890 );
print Dumper( \%hash );
print qq(\n);
my $json = encode_json \%hash;
print qq($json\n\n);
#------------------------------
$hash{cl_ip} += 0;
print Dumper( \%hash );
print qq(\n);
$json = encode_json \%hash;
print qq($json\n\n);
#------------------------------
$hash{cl_ip} = "209890";
print Dumper( \%hash );
print qq(\n);
$hash{cl_ip} += 0;
print Dumper( \%hash );
print qq(\n);
$json = encode_json \%hash;
print qq($json\n\n);
__END__
karl-mac-mini:monks karl$ ./json.pl
$VAR1 = {
'cl_ip' => 209890
};
{"cl_ip":209890}
$VAR1 = {
'cl_ip' => 209890
};
{"cl_ip":209890}
$VAR1 = {
'cl_ip' => '209890'
};
$VAR1 = {
'cl_ip' => 209890
};
{"cl_ip":209890}
My best regards, Karl
«The Crux of the Biscuit is the Apostrophe»
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: String to Integer, for json file
by Anonymous Monk on Dec 12, 2013 at 09:50 UTC
|
| [reply] [Watch: Dir/Any] |
|
|