Regex for Numbers Only: Integers, Decimals, Negative Values, and Leading Zeros
“Numbers only” sounds like a small validation rule, but the right regex depends on the number format you actually want to accept. A field may allow plain integers, decimal values, negative amounts, commas, or leading zeros. Those choices are different grammars. A pattern that is correct for 42 may reject -42, and a pattern that accepts 1,234.50 may also accept a badly placed comma unless it is written carefully.
This guide builds the patterns one step at a time. It covers ASCII digits, Unicode behavior, whole numbers, decimals, signed values, thousands separators, and leading zeros. The examples use JavaScript and Python, with copy-ready snippets you can adapt to a form, search box, import script, or API boundary.
The basic regex for numbers only
If “numbers only” means one or more ASCII digits and nothing else, start here:
^[0-9]+$ The anchors require the entire input to match. [0-9] matches one digit from 0 through 9, and + requires at least one of them. The pattern accepts 0, 7, and 2026. It rejects an empty string, spaces, a decimal point, a minus sign, and letters.
You will also see this shorter version:
^\d+$ It is often fine, but \d is not identical in every regex engine. If your application has to accept ASCII digits only, [0-9] makes that policy visible and predictable.
\d versus [0-9]: the Unicode detail
In JavaScript without special Unicode property escapes, \d matches the ASCII digits 0–9. The same is true for the common JavaScript form /^\d+$/. Python is different: the default re behavior treats \d as a Unicode decimal-digit category, so it can match characters such as Arabic-Indic digits. Python’s [0-9] remains the explicit ASCII range.
That difference matters when a value is sent to a system that expects ordinary ASCII text, when you convert the match with an older parser, or when a database field has a strict input contract. Use the narrowest rule that matches your requirements:
ASCII digits in any engine:
^[0-9]+$
JavaScript digits:
/^\d+$/
Python ASCII digits:
re.fullmatch(r"[0-9]+", value)
Python Unicode decimal digits:
re.fullmatch(r"\d+", value) In Python, you can also use the re.ASCII flag if you want shorthand classes such as \d to use ASCII semantics. Do not assume that moving a pattern from Python to JavaScript, or from one library to another, preserves every character-class rule.
Regex for non-negative integers
A non-negative integer has no decimal point and no sign. The basic pattern is the same as the numbers-only pattern:
^[0-9]+$ Use this for quantities, page numbers, counts, or an ID field when zero is allowed. If zero is not valid and the value must be positive, require a non-zero first digit:
^[1-9][0-9]*$ This accepts 1, 25, and 9000, but rejects 0 and 007. That last result is intentional for a canonical positive integer. If leading zeros are part of the format, use a different pattern rather than adding a loose optional group.
Regex for decimals
For a non-negative decimal with digits on both sides of the decimal point, use:
^[0-9]+\.[0-9]+$ It accepts 12.50 and 0.75, while rejecting 12, .75, and 12.. Requiring digits on both sides is a useful default for data exchanged between systems.
If your UI should accept either an integer or a decimal, make the decimal part optional:
^[0-9]+(?:\.[0-9]+)?$ To limit the value to two decimal places, change the final group to {1,2}:
^[0-9]+(?:\.[0-9]{1,2})?$ This controls the shape, not the numeric range. It accepts 999999.99 just as readily as 9.99. Check maximum and minimum values in code after the regex succeeds.
Allowing negative numbers and an optional plus sign
To allow negative or positive integers, put an optional sign at the beginning:
^[+-]?[0-9]+$ The character class [+-] means either plus or minus. The question mark makes the sign optional. This accepts -42, +42, and 42. If plus signs should be rejected but negative values are allowed, use -? instead:
^-?[0-9]+$ For signed decimals, combine the same sign prefix with the decimal rule:
^[+-]?[0-9]+(?:\.[0-9]+)?$ Keep a policy decision in mind: should -0 be accepted? Regex sees it as a valid sign followed by digits. If negative zero has a special meaning in your application, handle that after matching.
Thousands separators and formatted numbers
For comma-separated groups in the familiar US style, a strict pattern is:
^[+-]?(?:[0-9]+|[0-9]{1,3}(?:,[0-9]{3})+)(?:\.[0-9]+)?$ The first alternative accepts an unformatted number such as 1234.50. The second accepts correctly grouped values such as 1,234 and 12,345,678.90. The comma group repeats only after an initial group of one to three digits, so malformed values such as 1,23, 12,34,567, and 1,2345 fail.
If commas are required for values with four or more integer digits, use a stricter version:
^[+-]?[0-9]{1,3}(?:,[0-9]{3})+(?:\.[0-9]+)?$ Formatting conventions vary by locale. European input may use a period for grouping and a comma for decimals, while some locales use a narrow no-break space. Do not silently treat every comma as a thousands separator. Parse the locale deliberately, or normalize a known format before numeric conversion.
Leading zeros: decide what they mean
Leading zeros are not automatically wrong. They may be required for an account code, a two-digit month, or a fixed-width identifier. They are usually unwanted when the field represents a canonical number.
For an integer with no leading zeros except the value zero itself, use:
^(?:0|[1-9][0-9]*)$ This accepts 0, 7, and 105, but rejects 00 and 007. For exactly two digits, including values such as 07, use ^[0-9]{2}$. For a fixed three-digit code, use ^[0-9]{3}$. These patterns describe a code, not a number that should be converted without preserving its text.
JavaScript examples
JavaScript regex literals are convenient for one-off checks. Use test() for a boolean result and trim only if surrounding whitespace is allowed by your input contract.
const integerOnly = /^[0-9]+$/;
const signedDecimal = /^[+-]?[0-9]+(?:\.[0-9]+)?$/;
integerOnly.test("42"); // true
integerOnly.test("42.5"); // false
signedDecimal.test("-42.5"); // true
signedDecimal.test(" 42.5"); // false When using new RegExp(), remember that the JavaScript string literal processes backslashes first:
const pattern = new RegExp("^[+-]?[0-9]+(?:\\.[0-9]+)?$");
const valid = pattern.test(value); The regex engine must receive \. to match a literal dot, so the string source contains \\.. A regex literal avoids that extra layer of escaping.
Python examples
Python raw strings make regex code easier to read because most backslashes are passed through unchanged. For full-string validation, re.fullmatch() expresses the intent directly.
import re
integer_only = re.compile(r"[0-9]+")
signed_decimal = re.compile(r"[+-]?[0-9]+(?:\.[0-9]+)?")
integer_only.fullmatch("42") # Match object
integer_only.fullmatch("42.5") # None
signed_decimal.fullmatch("-42.5") # Match object If you intentionally want Unicode decimal digits in Python, compile r"\d+" without re.ASCII. If you want the shorthand to behave like ASCII, write re.fullmatch(r"\d+", value, flags=re.ASCII), or use [0-9]+ and make the rule obvious.
Copy-ready regex reference
ASCII digits only:
^[0-9]+$
Positive integer, no leading zeros:
^[1-9][0-9]*$
Integer with zero allowed, no extra leading zeros:
^(?:0|[1-9][0-9]*)$
Unsigned decimal:
^[0-9]+\.[0-9]+$
Integer or decimal:
^[0-9]+(?:\.[0-9]+)?$
Signed integer:
^[+-]?[0-9]+$
Signed decimal:
^[+-]?[0-9]+(?:\.[0-9]+)?$
Two decimal places maximum:
^[+-]?[0-9]+(?:\.[0-9]{1,2})?$
US-style grouped number:
^[+-]?(?:[0-9]+|[0-9]{1,3}(?:,[0-9]{3})+)(?:\.[0-9]+)?$ Why full-string matching matters
Validation and searching are different jobs. A pattern such as [0-9]+ can find a run of digits inside Room 42, but that does not mean the complete value is numeric. For validation, anchor the pattern or use an API that explicitly performs a full match. In most regex flavors, ^ marks the beginning and $ marks the end. The anchors turn a substring search into a whole-input check.
There is one newline detail worth testing. Some engines let $ match just before a final newline, which can make an input containing 42\n look valid. If your environment supports an absolute-end anchor such as \z, use the engine-specific option when you need that strictness. In JavaScript, checking the value after removing an allowed line ending, or using a full-input comparison in application code, makes the policy clearer. Do not add a multiline flag to a validation regex unless you specifically want each line to be checked independently.
Examples of accepted and rejected values
A short test matrix is often more useful than a complicated pattern. The table below assumes that the rule is ASCII digits only, with no signs, spaces, decimal points, or separators. When your product changes that policy, update both the regex and its tests.
| Input | Digits-only result | Reason |
|---|---|---|
42 | Accept | ASCII digits only |
0 | Accept | Zero is a digit sequence |
007 | Accept | Leading zeros are not excluded |
-42 | Reject | Contains a minus sign |
42.5 | Reject | Contains a decimal point |
42 | Reject | Contains surrounding spaces |
Whitespace, empty values, and normalization
Decide what to do with whitespace before writing the pattern. A web form may receive a value copied with a trailing space, while an API may require the client to send an exact token. If spaces are allowed around a number, normalize first and validate the normalized value; for example, trim the string once, then apply ^[+-]?[0-9]+$. If spaces are meaningful or should produce an error, do not hide them with a broad expression such as \s*.
Empty input is another separate rule. The quantifier + requires at least one character, while * also accepts an empty string. For a required field, keep + and report “required” separately from “invalid number.” For an optional field, check for an empty value before running the numeric regex. This produces clearer error messages and avoids accidentally treating a missing value as zero.
Validation versus extraction
Do not use a validation pattern as an extraction pattern without changing the surrounding logic. For example, \d+ can extract 123 from Order 123A, but a numbers-only field should reject the whole string. Conversely, a strict anchored pattern may be the wrong tool when you are intentionally finding every number in a sentence. Choose anchors, capture groups, and iteration based on whether the task is “is this value valid?” or “where are the numbers?”
Frequently asked questions
What is the simplest regex for numbers only? For one or more ASCII digits, use ^[0-9]+$. It does not allow signs, decimal points, commas, or whitespace.
Should I use \d or [0-9]? Use [0-9] when the input contract requires ASCII digits. It avoids relying on engine-specific Unicode behavior. Use \d only when you have checked the target engine and intentionally want its digit semantics.
Can regex check whether a number is between two values? It can describe small, fixed ranges, but range expressions become difficult to maintain quickly. Match the permitted format with regex, then parse the value and compare it numerically in code.
Why does my decimal regex reject .5? A pattern using [0-9]+\.[0-9]+ requires digits on both sides of the dot. If your interface deliberately accepts .5, use a separate optional-integer-part rule and test that format explicitly.
Regex validation is only the first check
A regex can confirm the spelling of a value. It does not safely replace numeric parsing. After a match, convert the value using the language’s number type, check the allowed range, decide how to handle whitespace, and consider whether floating-point precision is suitable for money. For monetary values, a decimal library or integer minor-unit representation is often safer than a binary floating-point number.
Test the edge cases your product actually accepts: empty input, zero, a negative value, a decimal with too many places, a misplaced separator, a trailing newline, and non-ASCII digits. Keep the regex small enough that another developer can tell what policy it implements. The best “numbers only” regex is the one whose accepted formats match the rest of your application.