Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How can I match a number with an optional sign and decimal part?

Quick answer

For a deliberately limited ASCII-style format, use ^[+-]?[0-9]+(?:\.[0-9]+)?$ in Python’s re module. It allows one optional plus or minus sign, requires at least one digit, and allows an optional dot followed by at least one digit. It does not allow a leading-dot fraction such as .5 or locale-specific decimal separators, so treat it as a text-shape check, not a universal numeric validator. [S1]

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I need a regular expression for a number that may start with + or -, may have a decimal part, and must otherwise contain digits. What pattern should I use?

Geez

Assuming your intended format requires at least one digit before the decimal point and, if a decimal point appears, at least one digit after it, use this Python re pattern:

r'^[+-]?[0-9]+(?:\.[0-9]+)?$'

The sign is optional; the digits before the decimal are required. The final group makes the decimal point and its following digits optional as one unit. The ^ and $ anchors specify the beginning and end of the string in Python’s regular-expression context. [S1]

For example, 12, -12, +12, 3.14, and -0.5 fit that stated shape. This is intentionally narrower than every way people write numbers.

Follow-up question

Can you break down the pieces? I’m especially unsure why the decimal part is grouped.

Geez

Read the pattern from left to right:

  1. ^ starts the match at the beginning of the string.
  2. [+-]? allows one plus or minus sign, or no sign.
  3. [0-9]+ requires one or more digits before any decimal point.
  4. (?:\.[0-9]+)? allows either no fractional part, or a literal dot followed by one or more digits.
  5. $ anchors the pattern at the string’s end. [S1]

The group matters because the dot and its following digits belong together: making the whole group optional allows an integer such as 12, without also allowing a dangling dot such as 12.. The ?: form is a non-capturing group; here, grouping is used to apply the optional marker to the whole decimal portion.

Follow-up question

Which inputs would it reject? I need to explain the boundary to someone using a form.

Geez

Under the format above, the pattern rejects .5 because there are no digits before the dot; 5. because the dot has no following digit; and an empty string because at least one digit is required. It also rejects --5, 1e3, and 1,5: those forms are not included in this deliberately limited pattern. [S1]

That last point is important. A comma may be a decimal separator in some conventions, but this pattern allows a dot, not locale-specific separators. It checks whether text has the chosen shape; it does not establish that the value follows every numeric convention or decide how an application should parse it. [S1]

Follow-up question

What’s a concise way to test examples and document the decision in my code review?

Geez

Here is a small Python example you can adapt. The expected results are illustrative checks for the stated pattern, not a complete test suite:

import re

number_text = re.compile(r'^[+-]?[0-9]+(?:\.[0-9]+)?$')

examples = {
    '12': True,
    '-12': True,
    '+3.14': True,
    '.5': False,
    '5.': False,
    '1,5': False,
}

for text, expected in examples.items():
    print(text, bool(number_text.fullmatch(text)), expected)

A useful review note is: “Accept an optional leading sign, one or more digits, and optionally a dot plus one or more digits. This format requires digits on both sides of a decimal point and uses a dot as the separator.” Python’s re documentation gives this pattern for the limited format and notes that it does not cover leading-dot fractions or locale-specific separators. [S1] If your product needs those forms, define them explicitly before changing the pattern.

A practical checklist

  • Decide whether at least one digit must appear before a decimal point.

  • Decide whether a decimal point must have digits after it.

  • Choose which sign characters and decimal separator the input format allows.

  • Use ^[+-]?[0-9]+(?:\.[0-9]+)?$ for the stated dot-decimal format in Python re.

  • Test representative accepted and rejected strings, including boundary cases.

  • Keep text-shape matching separate from parsing or locale-specific numeric rules.

A few more useful answers

Why does the pattern use `[0-9]` instead of `\d`?

This pattern explicitly describes the ASCII-style digit range [0-9] in the stated format. If your input requirements differ, define the desired digit set rather than assuming this pattern covers every numeric convention. [S1]

How can I allow `.5` as well as `0.5`?

That is a different format from the one shown: the pattern here requires digits before the decimal point. Specify the allowed forms first, then adjust and test the pattern to match those requirements.

Does a match prove the input is a valid number everywhere?

No. It only matches the chosen text shape. The documented pattern excludes leading-dot fractions and locale-specific decimal separators, and does not establish broader numeric conventions. [S1]

Sources

References used for this guide.

  1. [S1] Python 3 regular-expression operations: character classes and quantifiers
    docs.python.org · Checked
  2. [S2] MDN: JavaScript regular-expression quantifiers
    developer.mozilla.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work