I'm trying to write a regular expression for strings that are numbers in JSON. I'm still new to writing Regular expressions, I found a diagram of a machine for JSON numbers here , but I'm not sure how to attack it.

Here are some strings that should be found by the regex. "22", "55.75466", "-44.565" "55e-2" "69234.2423432 E78" Any help is appreciated!

  • 1
    You should probably explain what you mean by "strings that are numbers in JSON", preferably with an example. "JSON numbers" is a little puzzling too. – Denys Séguret Nov 12 '12 at 8:57
  • 4
    According to json.org your final example shouldn't be considered a number due to the space. – slackwing Nov 12 '12 at 9:06

For reference, here's the "number" diagram from http://www.json.org/fatfree.html:

JSON number

The regex that should match this is:

  • could you, or someone explain to me how you got the answer? – Joe Crawley Nov 12 '12 at 9:29
  • 4
    I just followed the diagram, left to right. For example, first you choose between going down to encounter a -, or go straight, skipping the -. In regex this can be represented as -?, or, "Zero or one -s." Then, the path splits again, between a 0 and a series of digits starting with a 1 (so as to prevent numbers like 0123 since JSON doesn't support octal). In regex this can be represented by "alternation", which looks like this: (?:xxx|yyy) where xxx and yyy are possible "paths". And so on. If you need a deeper explanation of the regex, let us know. – slackwing Nov 12 '12 at 9:33
  • neg sign "-" by itself is a valid json number according to your regex. would not bang – drgs Jul 1 '17 at 11:52
  • 1
    @drgs - The (?:0|[1-9]\d*) guarantees at least a digit. Still don't have to bang if you don't want, tho. – slackwing Jul 1 '17 at 19:56

acheong87's answer should provide the regex that you require. However, if you are just trying to check if a string returned via JSON "is a number" then you can do this:

var valueAsString = "55e-2";
var isANumber = !isNaN(valueAsString);

Building on Andrew Cheong's fine answer, here's a version that is Bash-compatible. The subtle differences take a while to get just right.


In the end, the differences are just that \d is replaced by [[:digit:]] and the ?: are dropped from the alternation clauses.

Here's a script you can paste into a Bash shell to verify its performance. The regex is surrounded by ^ and $ to match the start and end of line respectively, to check for stray trailing or leading characters.

while read line; do
    if [[ $line =~ ^-?(0|[1-9][[:digit:]]*)(\.[[:digit:]]+)?([eE][+-]?[[:digit:]]+)?$ ]]
        echo "$line is a number"
        echo "$line NOT a number"
done << END
69234.2423432 E78

In Bash 4.4.12, I get:

1 is a number
-1 is a number
a NOT a number
1a NOT a number
a1 NOT a number
-1.0 is a number
1. NOT a number
.0 NOT a number
. NOT a number
-.0 NOT a number
+ NOT a number
+0 NOT a number
+.0 NOT a number
22 is a number
55.75466 is a number
-44.565 is a number
55e-2 is a number
69234.2423432 E78 NOT a number
69234.2423432E78 is a number
- NOT a number
0123 NOT a number

Your Answer

