Because of the recursive nature of JSON (nested {...}-s), regex is not suited to validate it. Sure, some regex flavours can recursively match patterns* (and can therefor match JSON), but the resulting patterns are horrible to look at, and should never ever be used in production code IMO!
* Beware though, many regex implementations do not support recursive patterns. Of the popular programming languages, these support recursive patterns: Perl, .NET, PHP and Ruby 1.9.2
Most modern regex implementations allow for recursive regexpressions, which can verify a complete JSON serialized structure. The json.org specification makes it quite straightforward.
It works quite well in PHP with the PCRE functions . Should work unmodified in Perl; and can certainly be adapted for other languages. Also it succeeds with the JSON test cases.
Simpler RFC4627 verification
A simpler approach is the minimal consistency check as specified in RFC4627, section 6. It's however just intended as security test and basic non-validity precaution:
var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
eval('(' + text + ')');
For "strings and numbers", I think that the partial regular expression for numbers:
-?(?:0|[1-9]\d*)(?:\.\d+)(?:[eE][+-]\d+)?
should be instead:
-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?
since the decimal part of the number is optional, and also it is probably safer to escape the - symbol in [+-] since it has a special meaning between brackets
Yes, it's a common misconception that Regular Expressions can match only regular languages. In fact, the PCRE functions can match much more than regular languages, they can match even some non-context-free languages! Wikipedia's article on RegExps has a special section about it.
JSON can be recognized using PCRE in several ways! @mario showed one great solution using named subpatterns and back-references. Then he noted that there should be a solution using recursive patterns(?R). Here is an example of such regexp written in PHP:
$regexString = '"([^"\\\\]*|\\\\["\\\\bfnrt\/]|\\\\u[0-9a-f]{4})*"';
$regexNumber = '-?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?';
$regexBoolean= 'true|false|null'; // these are actually copied from Mario's answer
$regex = '/\A('.$regexString.'|'.$regexNumber.'|'.$regexBoolean.'|'; //string, number, boolean
$regex.= '\[(?:(?1)(?:,(?1))*)?\s*\]|'; //arrays
$regex.= '\{(?:\s*'.$regexString.'\s*:(?1)(?:,\s*'.$regexString.'\s*:(?1))*)?\s*\}'; //objects
$regex.= ')\Z/is';
I'm using (?1) instead of (?R) because the latter references the entire pattern, but we have \A and \Z sequences that should not be used inside subpatterns. (?1) references to the regexp marked by the outermost parentheses (this is why the outermost ( ) does not start with ?:). So, the RegExp becomes 268 characters long :)
Anyway, this should be treated as a "technology demonstration", not as a practical solution. In PHP I'll validate the JSON string with calling the json_decode() function (just like @Epcylon noted). If I'm going to use that JSON (if it's validated), then this is the best method.
This way, once it identifies a construct that is not 'optional' (* or ?), it shouldn't try backtracking over it to try to identify it as something else.
As was written above, if the language you use has a JSON-library coming with it, use it to try decoding the string and catch the exception/error if it fails! If the language does not (just had such a case with FreeMarker) the following regex could at least provide some very basic validation (it's written for PHP/PCRE to be testable/usable for more users). It's not as foolproof as the accepted solution, but also not that scary =):
~^\{\s*\".*\}$|^\[\n?\{\s*\".*\}\n?\]$~s
short explanation:
// we have two possibilities in case the string is JSON
// 1. the string passed is "just" a JSON object, e.g. {"item": [], "anotheritem": "content"}
// this can be matched by the following regex which makes sure there is at least a {" at the
// beginning of the string and a } at the end of the string, whatever is inbetween is not checked!
^\{\s*\".*\}$
// OR (character "|" in the regex pattern)
// 2. the string passed is a JSON array, e.g. [{"item": "value"}, {"item": "value"}]
// which would be matched by the second part of the pattern above
^\[\n?\{\s*\".*\}\n?\]$
// the s modifier is used to make "." also match newline characters (can happen in prettyfied JSON)
if I missed something that would break this unintentionally, I'm grateful for comments!
I tried @mario's answer, but it didn't work for me, because I've downloaded test suite from JSON.org (archive) and there were 4 failed tests (fail1.json, fail18.json, fail25.json, fail27.json).
I've investigated the errors and found out, that fail1.json is actually correct (according to manual's note and RFC-7159 valid string is also a valid JSON). File fail18.json was not the case either, cause it contains actually correct deeply-nested JSON:
Looking at the documentation for JSON, it seems that the regex can simply be three parts if the goal is just to check for fitness:
The string starts and ends with either [] or {}
[{\[]{1}...[}\]]{1}
and
The character is an allowed JSON control character (just one)
...[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]...
or The set of characters contained in a ""
...".*?"...
All together:
[{\[]{1}([,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]|".*?")+[}\]]{1}
If the JSON string contains newline characters, then you should use the singleline switch on your regex flavor so that . matches newline. Please note that this will not fail on all bad JSON, but it will fail if the basic JSON structure is invalid, which is a straight-forward way to do a basic sanity validation before passing it to a parser.