Andurit Andurit - 1 year ago 108
JSON Question

Check if JSON LIKE string is valid - JS regex

I have CLI app where user provide a JSON. I need to check if JSON is valid.
I found somehting like this may work great:

function isJsonValid(str) {
try {
} catch (e) {
return false;
return true;

But while I debug my app i noticed that there is a little problem that all
from command are stripped.
so json as:

"key1": "value1",
"key2": "value2"

is changed to something as:


I need a regex which will check if this stripped JSON is valid somehow.

So result should looks like:

re.test({key1:value1,key2:value2}) // true
re.test({key1:value1}) // true
re.test({key1:value1,}) // false, extra comma
re.test({key1:value1, key2}) // false, missing value of key2
re.test({key1:value1, key2:value2) // false, missing closing }
re.test({key1:value1, key2:value2}}) // false, extra closing }

Can someone please help me with regex part? This is unfortunately really not my strong side.

Answer Source

As I mentioned in a comment above, the "stripped" JSON is of course no longer JSON at all. You have confirmed that you do not need to worry about nested objects or arrays, just a simple list of key:value pairs surrounded by curly brackets.

So, the following regex assumes that each key and value will be made up of "word" characters using the regex \w that is equivalent to [A-Za-z0-9_]:

var re = /^\{\w+:\w+(,\w+:\w+)*\}$/;

Obviously if you want to vary which characters are allowed as key names and values you can replace each \w with [A-Za-z0-9_] and just add or remove allowed characters as required.

EDIT: In a comment you mentioned allowing . in the key names and values. So using the case-insensitive i flag on the regex:

var re = /^\{[A-Z0-9._]+:[A-Z0-9._]+(,[A-Z0-9._]+:[A-Z0-9._]+)*\}$/i;

But you probably want to allow for optional white-space between all of the pieces, so I'd suggest adding \s* between all the tokens:

var re = /^\s*\{\s*[A-Z0-9._]+\s*:\s*[A-Z0-9._]+\s*(,\s*[A-Z0-9._]+\s*:\s*[A-Z0-9._]+\s*)*\}\s*$/i;

console.log( re.test('{key1:value1,key2:value2}') )   // true
console.log( re.test('{key1:value1}') )               // true
console.log( re.test(' { key1 : value1 , key2 : value2 ,  k3  :   v3  } ') ) // true
console.log( re.test(' { k.j.m : v.a2 , k2.a.b : v.32 ,  k3  :   v3  } ') ) // true
console.log( re.test('{key1:value1,}') )              // false, extra comma
console.log( re.test('{key1:value1, key2}') )         // false, missing value of key2
console.log( re.test('{key1:value1, key2:value2') )   // false, missing closing }
console.log( re.test('{key1:value1, key2:value2}}') ) // false, extra closing }

(Note that the bit I edited in to allow for . in the names will allow multiple . characters in a row, but I don't really want to keep coming back to update my answer as more requirements are added that weren't mentioned in the original post. If you want to keep it strictly one . in a row and no leading or trailing dots then just apply the same principle that the regex above used to make the commas work.)

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download