How do I check if a string is valid JSON in Python?
Solution 1
You can try to do json.loads()
, which will throw a ValueError
if the string you pass can't be decoded as JSON.
In general, the "Pythonic" philosophy for this kind of situation is called EAFP, for Easier to Ask for Forgiveness than Permission.
Solution 2
Example Python script returns a boolean if a string is valid json:
import json
def is_json(myjson):
try:
json.loads(myjson)
except ValueError as e:
return False
return True
Which prints:
print is_json("{}") #prints True
print is_json("{asdf}") #prints False
print is_json('{ "age":100}') #prints True
print is_json("{'age':100 }") #prints False
print is_json("{\"age\":100 }") #prints True
print is_json('{"age":100 }') #prints True
print is_json('{"foo":[5,6.8],"foo":"bar"}') #prints True
Convert a JSON string to a Python dictionary:
import json
mydict = json.loads('{"foo":"bar"}')
print(mydict['foo']) #prints bar
mylist = json.loads("[5,6,7]")
print(mylist)
[5, 6, 7]
Convert a python object to JSON string:
foo = {}
foo['gummy'] = 'bear'
print(json.dumps(foo)) #prints {"gummy": "bear"}
If you want access to low-level parsing, don't roll your own, use an existing library: http://www.json.org/
Great tutorial on python JSON module: https://pymotw.com/2/json/
Is String JSON and show syntax errors and error messages:
sudo cpan JSON::XS
echo '{"foo":[5,6.8],"foo":"bar" bar}' > myjson.json
json_xs -t none < myjson.json
Prints:
, or } expected while parsing object/hash, at character offset 28 (before "bar}
at /usr/local/bin/json_xs line 183, <STDIN> line 1.
json_xs
is capable of syntax checking, parsing, prittifying, encoding, decoding and more:
https://metacpan.org/pod/json_xs
Solution 3
I would say parsing it is the only way you can really entirely tell. Exception will be raised by python's json.loads()
function (almost certainly) if not the correct format. However, the the purposes of your example you can probably just check the first couple of non-whitespace characters...
I'm not familiar with the JSON that facebook sends back, but most JSON strings from web apps will start with a open square [
or curly {
bracket. No images formats I know of start with those characters.
Conversely if you know what image formats might show up, you can check the start of the string for their signatures to identify images, and assume you have JSON if it's not an image.
Another simple hack to identify a graphic, rather than a text string, in the case you're looking for a graphic, is just to test for non-ASCII characters in the first couple of dozen characters of the string (assuming the JSON is ASCII).
Related videos on Youtube
Comments
-
Joey Blake over 2 years
In Python, is there a way to check if a string is valid JSON before trying to parse it?
For example working with things like the Facebook Graph API, sometimes it returns JSON, sometimes it could return an image file.
-
John La Rooy about 13 yearsthe api should set the content type
-
jhocking about 13 yearsYou can't specify what data is returned in the API call? I'm not familiar with the Facebook API but that sounds really odd.
-
YOU about 13 yearsI have done once, but with codegolf way
-
Joey Blake about 13 yearsMost of the responses are json, but, if you call the profile photo it just returns the jpg
-
-
Joey Blake about 13 yearsI can see how that will work. Leads me to my next question. It throws a ValueError. What I want it to do at this point is return the offending string so I can do something else with it. So far, I've only gotten the error message and type.
-
John Flatness about 13 yearsWhat's wrong with just returning the string you passed to
loads
in the except clause? -
Joey Blake about 13 yearsnothing wrong with it, just a noob mistake on my part. It appears I just cant call file.read() twice. But I can set a variable and use it. And thats what I did.
-
wahrheit about 10 yearsjust a note... json.loads('10') doesn't throw the ValueError and I'm sure '10' is not a valid json ...
-
John Flatness about 10 yearsDespite the fact that the spec says that a JSON text must be an array or object, most encoders and decoders (including Python's) will work with any JSON value at the "top," including numbers and strings.
10
is a valid JSON number value. -
Kevin over 9 years@wahrheit: If you want to detect that as an error, check whether the return value from
json.loads()
is a dictionary or list. -
BomberMan over 9 years@JohnFlatness is there anyway to check file type.. whether it is json or XML? In my case user will do input an "URL" which might consist json or xml data. so is there any way to check the type in Python?
-
KravAn about 8 yearsdigits can be decoded as json... but than you'll have an exception when will try retrieve some parameter (TypeError: argument of type 'int' is not iterable)
-
lucastamoios over 7 yearsI think general solutions are good, but in this case, the
except
clause may hide any serious exception. Catching exceptions must be as restrictive as possible. -
Akshay about 7 yearsDo you think we should
del json_object
once validated? -
Christopher G about 7 yearsEAFP :"This clean and fast style is characterized by the presence of many try and except statements." Cue this-is-fine comic.
-
Myobis over 6 yearsUnfortunately, {"a":1,"a":2} passes this test whereas it has duplicate property keys. Most of the parsers don't complain and usually consider the latest property .. However, there is definitely a problem.
-
John Flatness over 6 years@Myobis the tricky bit is that the relevant standards either don't say anything at all about duplicate keys or only say that they "SHOULD" be avoided, so it's not really invalid even though it may be problematic. Python does let you get at those duplicates if you use
object_pairs_hook
. -
Braden Best almost 6 yearsWhy the hell isn't there a proper validation method? There should be a way to error check without killing canaries.
-
Braden Best almost 6 yearsWhat I'm getting at is: Just because Python allows for OO doesn't mean it's okay to ignore the other parts. I should have the option of either A. letting the function fail and using exceptions (the OO/Python way), or B. calling a function that returns a value (success or error) instead of throwing an exception, and then having my function, in turn, return a sentinel value that indicates an error, so that errors bubble up the call stack and can be used as necessary (the procedural/C way). Just as C++ doesn't force you to use exceptions (you can use errno), Python shouldn't force it, either
-
Braden Best over 4 years@EricLeschinski but there isn't a halting problem here. The program clearly raises an exception if an error occurs while parsing JSON. Therefore, the program knows when JSON input is invalid. Therefore, it is 100% possible to have a function that checks whether the input is valid without having to use
try
. #StopCanaryAbuse -
djvg about 3 yearsIn current versions of Python 3,
json.loads()
throws aJSONDecodeError
, which is (indeed) a subclass ofValueError
, with some useful extra information. See source. -
Eric Leschinski over 2 yearsEvery piece of software that json encodes data must be the same at origin and destination for decoding. The "json standard" is not a standard. Making JSON just as portable as CSV flatfiles, HTML, XML, PDF, or any other data storage format. The format works perfectly with itself, but nothing else. To prove this to yourself, encode json data with one library, and decode it with a different library. It works for very trivial arrangements, but throw the list of naughty strings in and exercise every json datastructure, now none of the json parsers are compatible with any other. Bazinga.
-
Eric Leschinski about 2 yearsDon't let the word "Standard" in "jSon" throw you, no JSON encoder and decoder library is compatible with any other library. Make sure your JSON encoder/decoder is the same one at origin encoding and destination decoding. JSON is about as "standard" with itself as HTML, CSV, XML, XLS, ODS. That's why you bring canaries with you into the coal mine if you don't know where your json is from