wydncwymsjgcs
wydncwymsjgcs

Reputation: 69

regular expression to match an odd number in a string

I'm trying to use a regular expression to match only odd numbers in a string. What I'm thinking is to detect whether the last digit of the number is odd or not, but now I can only find the first (n-1) digits except for the last one.

For example, the following code works for the odd number 13, which is perfect! But when it turns to 132, the code still returns 13, which definitely fails. So, how can I manipulate the code and let it work for all numbers (no matter how large it is) ending with odd digits? Thank you!

match= '(\s*\d*[13579]\s*)'
print(re.search(match, "The number 13 matches")) #<re.Match object; span=(10, 14), match=' 13 '>
print(re.search(match, "The number 132 matches")) #<re.Match object; span=(10, 13), match=' 13'>

Upvotes: 3

Views: 1817

Answers (5)

Alain T.
Alain T.

Reputation: 42133

Use a look ahead to check that the odd digit is not followed by another digit:

match = '\d*[13579](?!\d)'

Upvotes: 1

tdelaney
tdelaney

Reputation: 77377

You could do a non-greedy search of decimals \d*? followed by an odd number [13579] and a word boundary \b. Put it together

import re

tests = [("The number 13 matches", True), 
    ("The number 132 matches", False)]

for test, is_match in tests:
    match = re.search(r"\d*?[13579]\b", test)
    print(repr(test), bool(match), "PASS" if bool(match) == is_match else "FAIL")       

Upvotes: 1

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79435

You can use the regex, \d+[13579](?=\s|$) which can be explained as

  • \d+ : One or more digits
  • [13579] : 1, 3, 5, 7, or 9
  • (?=\s|$) : Positive lookahead assertion for whitespace or end of line

Demo:

import re
match= '\d+[13579](?=\s|$)'
print(re.search(match, "The number 13 matches")) 
print(re.search(match, "The number 132 matches"))

Output:

<re.Match object; span=(11, 13), match='13'>
None

Upvotes: 3

Ryszard Czech
Ryszard Czech

Reputation: 18631

Use

(?<!\d)\d*[13579](?!\d)

See regex proof.

EXPLANATION

--------------------------------------------------------------------------------
  (?<!                     look behind to see if there is not:
--------------------------------------------------------------------------------
    \d                       digits (0-9)
--------------------------------------------------------------------------------
  )                        end of look-behind
--------------------------------------------------------------------------------
  \d*                      digits (0-9) (0 or more times (matching
                           the most amount possible))
--------------------------------------------------------------------------------
  [13579]                  any character of: '1', '3', '5', '7', '9'
--------------------------------------------------------------------------------
  (?!                      look ahead to see if there is not:
--------------------------------------------------------------------------------
    \d                       digits (0-9)
--------------------------------------------------------------------------------
  )                        end of look-ahead

Python code:

import re
regex = r"(?<!\d)\d*[13579](?!\d)"
test_str = "The number 13 matches"
matches = re.search(regex, test_str)
if matches is not None:
    print(matches.group())

Results: 13.

Also word boundaries could be used:

\b\d*[13579]\b

Upvotes: 1

Cary Swoveland
Cary Swoveland

Reputation: 110725

You can match

\d+(?!\d)(?<=[13579])

23 132 87 74 101
^^     ^^    ^^^

Demo

\d+      # match one or more digits
(?!      # begin negative lookahead
  \d     # match a digit
)        # end negative lookahead
(?<=     # begin positive lookbehind
[13579]  # match an odd digit
)        # end positive lookbehind

(?!\d) could be replaced by (?=\D|$), a positive lookahead that asserts that the match is followed by a non-digit or is at the end of the string.

Upvotes: 3

Related Questions