ruby JSON.parse fails on decimal numbers with point but without fractions - json

I have a json string like this :
{"weight": 56.}
I can enter this string into NodeJS interpreter and get a parsed hash as a result:
$ js
> {"Weight":56.}
{ Weight: 56 }
> {"Weight":56}
{ Weight: 56 }
as you see, NodeJS accepts both inputs with identical result
But in Ruby, for the same string I get
JSON::ParserError: ... unexpected token
until I remove '.' after the number
sample session :
irb...> s='{"Weight":56.}'
=> "{\"Weight\":56.}"
irb...> JSON.parse(s)
JSON::ParserError: 784: unexpected token at '{"Weight":56.}'
...
irb...> s='{"Weight":56}'
=> "{\"Weight\":56}"
irb...> JSON.parse(s)
=> {"Weight"=>56}
Can anything be done to Ruby JSON library to improve its conformance to JS ?
Now I have to filter these stray dec.points by regular expressions before parsing them as JSON

Related

python error on string format with "\n" exec(compile(contents+"\n", file, 'exec'), glob, loc)

i try to construct JSON with string that contains "\n" in it like this :
ver_str= 'Package ID: version_1234\nBuild\nnumber: 154\nBuilt\n'
proj_ver_str = 'Version_123'
comb = '{"r_content": {0}, "s_version": {1}}'.format(ver_str,proj_ver_str)
json_content = json.loads()
d =json.dumps(json_content )
getting this error:
exec(compile(contents+"\n", file, 'exec'), glob, loc)
File "C:/Dev/python/new_tester/simple_main.py", line 18, in <module>
comb = '{"r_content": {0}, "s_version": {1}}'.format(ver_str,proj_ver_str)
KeyError: '"r_content"'
The error arises not because of newlines in your values, but because of { and } characters in your format string other than the placeholders {0} and {1}. If you want to have an actual { or a } character in your string, double them.
Try replacing the line
comb = '{"r_content": {0}, "s_version": {1}}'.format(ver_str,proj_ver_str)
with
comb = '{{"r_content": {0}, "s_version": {1}}}'.format(ver_str,proj_ver_str)
However, this will give you a different error on the next line, loads() missing 1 required positional argument: 's'. This is because you presumably forgot to pass comb to json.loads().
Replacing json.loads() with json.loads(comb) gives you another error: json.decoder.JSONDecodeError: Expecting value: line 1 column 15 (char 14). This tells you that you've given json.loads malformed JSON to parse. If you print out the value of comb, you see the following:
{"r_content": Package ID: version_1234
Build
number: 154
Built
, "s_version": Version_123}
This isn't valid JSON, because the string values aren't surrounded by quotes. So a JSON parsing error is to be expected.
At this point, let's take a look at what your code is doing and what you seem to want it to do. It seems you want to construct a JSON string from your data, but your code puts together a JSON string from your data, parses it to a dict and then formats it back as a JSON string.
If you want to create a JSON string from your data, it's far simpler to create a dict with your values and use json.dumps on that:
d = json.dumps({"r_content": ver_str, "s_version": proj_ver_str})

Retrieving of a file with mongofiles leads to a JSON error

I am trying to retrieve an xml file from my Mongo DB with mongofiles. I get a JSON parsing error. Here is an excerpt my terminal:
$ mongofiles -d anhalytics get_id 'ObjectId("5e7f56d30800611b17fc66b1")'
2020-09-15T16:55:33.205+0200 connected to: mongodb://localhost/
2020-09-15T16:55:33.205+0200 Failed: error parsing id as Extended JSON: invalid JSON number. Position: 18
I am using a MongoDB server version: 4.2.9
Here is the record of the target file
{
"_id" : ObjectId("5e7f56d30800611b17fc66b1"),
"filename" : "5e7f56d30800611b17fc66b0.tei.xml",
"aliases" : null,
"chunkSize" : NumberLong(261120),
"uploadDate" : ISODate("2020-03-28T13:53:23.708Z"),
"length" : NumberLong(35405),
"contentType" : null,
"md5" : "eeafae907c44b207071ccb6036148808"
}
Any idea why I am getting this error? Thanks!
The message error parsing id as Extended JSON indicates that the mongofiles tool had trouble parsing the id string that was provided on the command line.
That is done in parseOrCreateId function here: https://github.com/mongodb/mongo-tools/blob/master/mongofiles/mongofiles.go#L330
That function wraps the value from the command line in another string like {"_id":"%s"}, so the value actually passed to the bson.UnmarshalExtJSON function would have been
"{\"_id\":\"ObjectId(\"5e7f56d30800611b17fc66b1\")\"}"
Position 18 of that string, as called out in the error message is the quotation mark immediately preceding the hex string.

Fixing JSON::ParserError: 416: unexpected token at '{' without using EVAL

I'm trying to parse a Hash that is represented as a String, take this example:
arr = "[{\"key\"=>\"VALUE\"}, {\"key\"=>\"VAlUE\"}]"
JSON.parse arr
=> JSON::ParserError: 416: unexpected token at '{"key"=>"VALUE"}, {"key"=>"VALUE"}]'
Ok, that's unfortunate and I realize that it's not JSON I'm trying to parse. But I can do this:
arr = "[{\"key\"=>\"VALUE\"}, {\"key\"=>\"VALUE\"}]"
eval(arr)
=> [{"key"=>"VALUE"}, {"key"=>"VALUE"}]
That's cool but I don't want to use EVAL due to the security risk.
How can I achieve the same result that EVAL gets me but without using it?

Use JSON.parse to parse OpenStruct or a hash

I tried to parse a simple JSON like that:
JSON.parse({"pong": "ok"})
and it failed
2.4.0 :014 > JSON.parse({"pong": "ok"})
TypeError: no implicit conversion of Hash into String
from (irb):14
What's wrong here ? Why should I convert to String ?
Another try, with OpenStruct this time:
2.4.0 :001 > pong = OpenStruct.new(pong: 'OK')
=> #<OpenStruct pong="OK">
2.4.0 :002 > JSON.parse(pong)
TypeError: no implicit conversion of OpenStruct into String
from (irb):2
The same ?
Thank you
JSON.parse parses json and json means String:
JSON.parse('{"pong": "ok"}')
#⇒ {"pong"=>"ok"}
Also, you might parse json string into OpenStruct:
JSON.parse('{"pong":"ok"}', object_class: OpenStruct).pong
#⇒ "ok"

JSON no longer parsable after being sent through TCP in Ruby

I've created a basic client and server that pass a string, which I've changed to JSON instead. But the JSON string is only parsable before it gets sent through TCP. After it's sent, the string version is identical (after a chomp), but on the server side it no longer processes the JSON correctly. Here is some of my code (with other bits trimmed)
Some of the client code
require 'json'
require 'socket'
foo = {'a' => 1, 'b' => 2, 'c' => 3}
puts foo.to_s + "......."
foo.to_json
puts foo['b'] # => outputs the correct '2' answer
client = TCPSocket.open('localhost', 2000)
client.puts json
client.close;
Some of the server code
require 'socket'
require 'json'
server = TCPServer.open(2000)
while true
client = server.accept # Accept client
response = client.gets
print response
response = response.chomp
response.to_json
puts response['b'] # => outputs 'b'
end
The output 'b' should be '2' instead. How do I fix this?
Thanks
In your server you wrote response.to_json. This turns a string to JSON, then throws it away. And I don't like the .chomp, either.
Try
response = client.gets
hash = JSON.parse(response)
Now hash is a Ruby Hash object with your data in it, and hash['b'] should work correctly.
The problem is that .to_json does not parse JSON inside a string and replace itself with the result. It is used to convert the string into a format that is an acceptable JSON value.
require 'json'
string = "abc"
puts string
puts string.to_json
This will output:
abc
"abc"
The method is added to the String class by the JSON generator and it uses it internally to generate the JSON document.
But why does your response['b'] return "b"?
Because Ruby strings have a method called [] that can be used to:
Return a substring: "abc"[0,2] => "ab"
Return a single character from index: "abc"[1] => "b"
Return a substring if the string contains it: "abc"["bc"] => "bc", "abc"["fg"] => nil
Return a regexp match: "abc"[/^a([a-z])c/, 1] => "b"
and possibly some other ways I can't think of right now.
So this happens because your response is a string that has the character "b" in it:
response = "something with a b"
puts response["b"]
# outputs b
puts response["x"]
# outputs a blank line because response does not contain "x".
Instead of .to_json your code has to call JSON.parse or JSON.load:
data = JSON.parse(response)
puts data['b']