48

I'm learning regex and I would like to use a regular expression in Python to define only integers - whole numbers but not decimals.

I could make one that only allows numbers by using \d, but it also allows decimal numbers, which I don't want:

price = TextField(_('Price'), [
    validators.Regexp('\d', message=_('This is not an integer number, please see the example and try again')),
    validators.Optional()]) 

How can I change the code to only allow integers?

1
  • 1
    regexlib.com is gold for questions like these Commented Dec 21, 2011 at 7:49

6 Answers 6

117

Regexp work on the character base, and \d means a single digit 0...9 and not a decimal number.

A regular expression that matches only integers with a sign could be for example

^[-+]?[0-9]+$

meaning

  1. ^ - start of string
  2. [-+]? - an optional (this is what ? means) minus or plus sign
  3. [0-9]+ - one or more digits (the plus means "one or more" and [0-9] is another way to say \d)
  4. $ - end of string

Note: having the sign considered part of the number is ok only if you need to parse just the number. For more general parsers handling expressions it's better to leave the sign out of the number: source streams like 3-2 could otherwise end up being parsed as a sequence of two integers instead of an integer, an operator and another integer. My experience is that negative numbers are better handled by constant folding of the unary negation operator at an higher level.

Sign up to request clarification or add additional context in comments.

6 Comments

One minor point: \d means any decimal digit, so if you are using Python 3 it will match more than just 0..9. e.g. re.match("\d", "\u0665") will match (and also int("\u0665") gives 5).
This post is from forever ago, but in case somebody new stumbles upon it, technically the minus sign is an operator (in Python 3), not part of the integer: from spec.: "Note that numeric literals do not include a sign; a phrase like -1 is actually an expression composed of the unary operator ‘-‘ and the literal 1"
@en_Knight: this is IMO totally irrelevant. What the OP was asking is an expression to accept integer numbers for humans, not for Python 3. While having a "price" probably could qualify for non-negative numbers only, for example it can make a lot of sense accepting negative integers for a "price difference"... even when writing that accounting program using Python 3.
Some grammars define integer as + or - followed by one or more digits, ^[+\-]?[0-9]+$
@ChuckCottrill: added the + sign (not so common when parsing but indeed somewhat common when formatting). I've also added a note on why it's however a bad idea to consider the sign part of the number when parsing if you're aiming at a more complex parsers able to handle expressions.
|
16

You need to anchor the regex at the start and end of the string:

^[0-9]+$

Explanation:

^      # Start of string
[0-9]+ # one or more digits 0-9
$      # End of string

5 Comments

This doesn't allow negative integers... not sure if OP wants to avoid them
@6502: Well, since it's a validation for a price text field, I thought positive integers make more sense, but still +1 for your well-commented answer :)
Actually positive integers don't make much sense for a price text field, unless the price is in cents..
@wim: Nick explicitly asked for integers - that's the entire point of the question.
It's like a price but only in dollars. It's for a classifieds posting site where everything that is advertised is going to be in dollars and nothing in cents.
11

I prefer ^[-+]?([1-9]\d*|0)$ because ^[-+]?[0-9]+$ allows the string starting with 0.

RE_INT = re.compile(r'^[-+]?([1-9]\d*|0)$')


class TestRE(unittest.TestCase):
    def test_int(self):
        self.assertFalse(RE_INT.match('+'))
        self.assertFalse(RE_INT.match('-'))

        self.assertTrue(RE_INT.match('1'))
        self.assertTrue(RE_INT.match('+1'))
        self.assertTrue(RE_INT.match('-1'))
        self.assertTrue(RE_INT.match('0'))
        self.assertTrue(RE_INT.match('+0'))
        self.assertTrue(RE_INT.match('-0'))

        self.assertTrue(RE_INT.match('11'))
        self.assertFalse(RE_INT.match('00'))
        self.assertFalse(RE_INT.match('01'))
        self.assertTrue(RE_INT.match('+11'))
        self.assertFalse(RE_INT.match('+00'))
        self.assertFalse(RE_INT.match('+01'))
        self.assertTrue(RE_INT.match('-11'))
        self.assertFalse(RE_INT.match('-00'))
        self.assertFalse(RE_INT.match('-01'))

        self.assertTrue(RE_INT.match('1234567890'))
        self.assertTrue(RE_INT.match('+1234567890'))
        self.assertTrue(RE_INT.match('-1234567890'))

Comments

9

You are apparently using Django.

You are probably better off just using models.IntegerField() instead of models.TextField(). Not only will it do the check for you, but it will give you the error message translated in several langs, and it will cast the value from it's type in the database to the type in your Python code transparently.

Comments

0
import re

num="12.345678"

y = re.findall('\.[0-9.]+',num)

print(y)

Answer= ['.345678']

After that, you can convert string to float.

Comments

0

An old question.

Usually [+-]?[0-9]+ is sufficient, meaning on can have a plus or minus, then one must have at least one character zero to nine, then you may have more characters zero through nine.

Except when its not. Are these numbers?

  • "1_234" is allowed as Python integer of 1234, and lets people enter large numbers without getting lost.
  • "٥" is the Arabic Indic digit 5, matched by \d. Oddly, int("4٥6") == 456
  • Most validator ad a caret at the front and dollar sign at the end to force matching the entire string, e.g., ^[+-]?[0-9]+$
  • "(1,234)" is a standard accounting way of writing -1234 in the US, or -1.234 in the UK.

Once your regex is over about ten characters, switch to using an online system to create and check it. I recommend Regex101 but there are a million of them.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.