To determine if a string represents a numeric value (integer or float) in Python, you can use the following approaches. Each method addresses edge cases like leading/trailing whitespace, scientific notation (e.g., 1e3), and special values like NaN or Inf.
1. Using Exception Handling (Recommended)
Attempt to convert the string to a float and catch errors. This handles most valid numeric formats:
def is_number(s):
try:
s = s.strip() # Remove leading/trailing whitespace
if not s:
return False # Empty string after stripping
num = float(s)
# Optional: Exclude NaN/Inf (uncomment to disable)
# if math.isnan(num) or math.isinf(num):
# return False
return True
except ValueError:
return False
Example Usage:
print(is_number("123")) # True (int)
print(is_number("-123.45")) # True (float)
print(is_number("1e3")) # True (scientific notation)
print(is_number(" 123.45 ")) # True (whitespace stripped)
print(is_number("NaN")) # True (by default; returns False if uncommented)
print(is_number("12a3")) # False
print(is_number("")) # False
2. Using Regular Expressions
Match numeric patterns (integers, floats, scientific notation) with a regex. This avoids exceptions but requires precise pattern definition:
import re
def is_number_regex(s):
pattern = r"^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$"
return bool(re.fullmatch(pattern, s.strip()))
Regex Breakdown:
^[+-]?: Optional leading+or-.\d+\.?\d*: Matches integers (123) or floats with digits before the decimal (123.,123.45).|\.\d+: Matches floats starting with.(e.g.,.45).(?:[eE][+-]?\d+)?$: Optional scientific notation (e.g.,1e3,-2.5E-4).
Example Usage:
print(is_number_regex("123")) # True
print(is_number_regex(".45")) # True
print(is_number_regex("123.45")) # True
print(is_number_regex("1e3")) # True
print(is_number_regex("12a3")) # False
print(is_number_regex("NaN")) # False (regex excludes non-numeric strings)
Key Differences
| Method | Pros | Cons |
|---|---|---|
| Exception Handling | Handles all valid Python numeric formats. | Allows NaN/Inf by default. |
| Regex | Explicit control over valid patterns. | Complex regex; may miss edge cases. |
Handling Integers vs. Floats
To distinguish between integers and floats, extend the exception-handling method:
def is_integer(s):
try:
s = s.strip()
if not s:
return False
num = float(s)
# Check if the float is an integer and the string lacks a decimal point
return num.is_integer() and "." not in s
except ValueError:
return False
print(is_integer("123")) # True
print(is_integer("123.0")) # False (contains '.')
print(is_integer("123.5")) # False
Final Recommendation
Use exception handling for simplicity and coverage of edge cases. If you need to exclude NaN or Inf, uncomment the relevant checks. For strict pattern control (e.g., disallow leading zeros), use the regex method.