How to check if a string is a number in Python
Discover multiple ways to check if a string is a number in Python. Get tips, see real-world applications, and learn to debug common errors.

Developers often need to check if a string is a number in Python for data validation. The language provides built-in methods like isdigit() and isnumeric() for this common task.
In this article, you'll explore various techniques to validate numeric strings, from simple methods to more complex solutions. You'll find practical tips, see real-world applications, and get advice to debug common errors.
Using the isdigit() method
text = "12345"
result = text.isdigit()
print(f"Is '{text}' a number? {result}")--OUTPUT--Is '12345' a number? True
The isdigit() method offers a direct way to confirm if a string contains only digits. It returns True for the string "12345" because every character is a numerical digit. This makes it a quick and efficient choice for validating simple, non-negative integers.
However, you should be aware of its limitations. The method will return False for any string that includes characters other than the digits 0-9, such as:
- Negative signs (e.g.,
"-50") - Decimal points (e.g.,
"99.9") - Spaces or other separators
Basic string validation methods
While isdigit() is great for simple integers, Python offers more versatile tools like isnumeric(), try/except blocks, and regular expressions for handling a wider range of numeric formats.
Using isnumeric() and isdecimal() for number detection
text1, text2, text3 = "123", "½", "⑦"
print(f"{text1}: isdigit={text1.isdigit()}, isnumeric={text1.isnumeric()}, isdecimal={text1.isdecimal()}")
print(f"{text2}: isdigit={text2.isdigit()}, isnumeric={text2.isnumeric()}, isdecimal={text2.isdecimal()}")
print(f"{text3}: isdigit={text3.isdigit()}, isnumeric={text3.isnumeric()}, isdecimal={text3.isdecimal()}")--OUTPUT--123: isdigit=True, isnumeric=True, isdecimal=True
½: isdigit=False, isnumeric=True, isdecimal=False
⑦: isdigit=True, isnumeric=True, isdecimal=False
The isnumeric() method is more inclusive than isdigit(), recognizing a wider range of numeric characters. Meanwhile, isdecimal() is the most restrictive of the three. The key difference lies in what each method considers a "number":
isdecimal()only accepts strings containing the digits 0-9.isdigit()is broader, also accepting special digits like circled numbers ("⑦").isnumeric()is the most comprehensive, covering fractions ("½"), superscripts, and other numeric symbols.
Using try/except to validate numeric strings
def is_number(text):
try:
float(text)
return True
except ValueError:
return False
print(is_number("123")) # Integer
print(is_number("123.45")) # Float
print(is_number("abc")) # Not a number--OUTPUT--True
True
False
Using a try/except block is a robust way to check if a string can be treated as a number. The code attempts to convert the string to a float(). If successful, it returns True. If the conversion fails—for instance, with non-numeric text—it triggers a ValueError, which the except block catches to return False.
This method is especially useful because it handles formats that isdigit() can't, such as:
- Strings with decimal points (e.g.,
"123.45") - Negative numbers (e.g.,
"-50")
Using regular expressions for number validation
import re
def is_number_regex(text):
pattern = r'^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$'
return bool(re.match(pattern, text))
print(is_number_regex("123")) # Integer
print(is_number_regex("-123.45")) # Negative float
print(is_number_regex("1.23e-4")) # Scientific notation--OUTPUT--True
True
True
Regular expressions offer the most control for validating complex numeric strings. The is_number_regex function uses Python's re module with re.match to check if a string conforms to a specific pattern. This approach is powerful because it can handle formats that other methods miss, such as:
- Integers and negative numbers
- Floats with decimal points
- Strings using scientific notation, like
"1.23e-4"
While the patterns themselves can be complex to write, they are unmatched for precision when you need to define custom validation rules.
Advanced validation techniques
While built-in methods and regular expressions handle many cases, you can create safer and more reusable validation logic with advanced tools and custom structures.
Using ast.literal_eval() for safe type checking
import ast
def is_number_literal(text):
try:
value = ast.literal_eval(text)
return isinstance(value, (int, float, complex))
except (ValueError, SyntaxError):
return False
print(is_number_literal("123")) # Integer
print(is_number_literal("12.3")) # Float
print(is_number_literal("'123'")) # String of digits (not a number)--OUTPUT--True
True
False
The ast.literal_eval() function offers a secure way to parse strings into Python data types. Unlike the risky eval() function, it only processes literal structures—like strings, lists, and numbers—and won't execute arbitrary code. This function first evaluates the string, then uses isinstance() to check if the resulting object is a numeric type.
This two-step process is what makes it so effective:
- It correctly identifies integers, floats, and complex numbers.
- It distinguishes a true number from a string that just contains digits, like
"'123'", which correctly returnsFalse.
Creating a flexible number validation function
def is_numeric(text, allow_scientific=True, allow_negative=True, allow_complex=False):
if not text:
return False
try:
value = complex(text) if allow_complex else float(text)
if not allow_negative and value.real < 0:
return False
if not allow_scientific and ('e' in text.lower() or 'E' in text):
return False
return True
except ValueError:
return False
print(is_numeric("123"), is_numeric("-456", allow_negative=False))--OUTPUT--True False
This custom is_numeric function offers a flexible way to validate numbers by letting you set the rules. It uses optional arguments to tailor the validation logic to your specific needs.
- The
allow_negativeflag can permit or block negative numbers. - You can use
allow_scientificto control whether strings in scientific notation are accepted. - The
allow_complexparameter enables validation for complex numbers.
The function works by first trying to convert the string, then applying your rules. For instance, calling is_numeric("-456", allow_negative=False) returns False because the flag explicitly disallows negative values.
Implementing a NumberValidator class
class NumberValidator:
@staticmethod
def is_integer(text):
if not text or (text[0] == '-' and len(text) == 1):
return False
return text.lstrip('-').isdigit()
@staticmethod
def is_float(text):
try:
float(text)
return '.' in text or 'e' in text.lower()
except ValueError:
return False
validator = NumberValidator()
print(f"Is integer: {validator.is_integer('-123')}, Is float: {validator.is_float('45.67')}")--OUTPUT--Is integer: True, Is float: True
Creating a NumberValidator class is a clean way to organize your validation logic into a reusable structure. Since the methods are defined with @staticmethod, you can call them directly from the class without needing to create an instance first, which keeps your code tidy.
This implementation provides two specific checks:
- The
is_integermethod correctly identifies negative integers by stripping the leading-before checking the remaining characters withisdigit(). - The
is_floatmethod confirms a string can be converted to afloatand also contains a decimal point or scientific notation, distinguishing it from an integer.
Move faster with Replit
Replit is an AI-powered development platform that comes with all Python dependencies pre-installed, so you can skip setup and start coding instantly. With Agent 4, you can go from an idea to a working product by describing what you want to build. It handles everything from writing code and connecting to APIs to managing databases and deployment.
Instead of piecing together individual techniques, you can build complete apps that use number validation for practical tasks:
- A data validation tool for a user signup form that ensures age and zip code fields only accept integers.
- A simple loan calculator that correctly handles decimal and negative inputs for interest rates or payments.
- A data cleaning utility that automatically identifies and converts numeric strings in a raw dataset for analysis.
Simply describe your app, and Replit will write the code, test it, and fix issues automatically, all within your browser.
Common errors and challenges
Even simple number validation can lead to tricky bugs, but you can avoid them by watching out for these common pitfalls.
- The
isdigit()method can be misleading because it recognizes more than just the digits 0-9. It returnsTruefor various Unicode characters that represent digits, like circled numbers. If you only want to validate standard integers,isdecimal()is a safer and more restrictive choice. - When using a
try/exceptblock, avoid catching exceptions too broadly. A genericexceptclause can hide unrelated errors, making your code difficult to debug. Always specify the error you expect to catch—in this case,except ValueError—to ensure you're only handling failed numeric conversions. - Regular expressions are precise but notoriously difficult to get right. A common mistake is writing a pattern that's either too strict and rejects valid numbers or too permissive and accepts invalid formats. Always test your regex against edge cases like empty strings, multiple decimal points, and misplaced signs.
Handling non-English numerals with isdigit()
The isdigit() method can cause unexpected issues when your application needs to support multiple languages. It returns True for various Unicode characters that represent digits, not just 0-9, which can lead to validation errors. The following code demonstrates this behavior.
def validate_user_age(age_input):
if not age_input.isdigit():
return "Error: Please enter digits only"
return f"Valid age: {age_input}"
print(validate_user_age("30")) # Regular digits
print(validate_user_age("३०")) # Hindi numerals
print(validate_user_age("三十")) # Chinese numerals (not digits)
The validate_user_age function returns an error for Chinese numerals because isdigit() only recognizes Unicode digit characters, not all numeric symbols. This creates inconsistent validation for international inputs. The following code demonstrates a more reliable approach.
def validate_user_age(age_input):
if not age_input.isnumeric():
return "Error: Please enter numeric characters"
return f"Valid age: {age_input}"
print(validate_user_age("30")) # Regular digits
print(validate_user_age("३०")) # Hindi numerals
print(validate_user_age("三十")) # Chinese numerals (not digits)
The corrected function swaps isdigit() for isnumeric(). This change makes the validation more reliable for international applications because isnumeric() recognizes a broader set of numeric characters, like Hindi numerals. It correctly validates both "30" and "३०" while still rejecting non-digit text like Chinese numerals. You should opt for isnumeric() whenever your application might handle user input from different languages to prevent unexpected validation failures.
Avoiding silent failures in try/except validation
Avoiding silent failures in try/except validation
Using a broad except clause is risky because it can cause silent failures. When a conversion fails, returning a default value like 0 masks the original error. This can silently corrupt your data, making debugging much harder. The following code demonstrates this.
def convert_to_number(value):
try:
return float(value)
except:
return 0 # Silent failure
data = ["42", "3.14", "error", "98.6"]
converted = [convert_to_number(item) for item in data]
print(converted)
The generic except clause in convert_to_number causes the invalid string "error" to become 0, corrupting the final list and hiding the failure's root cause. The corrected code below shows a better approach to handling exceptions.
def convert_to_number(value):
try:
return float(value)
except ValueError as e:
print(f"Couldn't convert '{value}': {e}")
return None
data = ["42", "3.14", "error", "98.6"]
converted = [convert_to_number(item) for item in data]
print([x for x in converted if x is not None])
The corrected function improves error handling by catching a specific ValueError. This prevents it from hiding unrelated bugs. Instead of returning a default value like 0, it returns None and prints a message, making it clear which conversions failed. This is especially important in data processing, where you need to identify and handle invalid entries without silently corrupting your results. You can then filter out the None values to create a clean dataset.
Fixing common regex pattern mistakes for number validation
Fixing common regex pattern mistakes for number validation
Regular expressions are powerful but can be tricky. A common mistake is creating a pattern that's too strict, accidentally rejecting valid numbers. For example, a regex might fail to match integers or numbers that start with a decimal point. The validate_decimal function below demonstrates this issue.
import re
def validate_decimal(number_str):
pattern = r'^\d+\.\d+$' # Only matches numbers with decimal points
return bool(re.match(pattern, number_str))
print(validate_decimal("42")) # Integer
print(validate_decimal("3.14159")) # Decimal
print(validate_decimal(".5")) # Leading decimal
The pattern r'^\d+\.\d+$' is too rigid. It requires digits on both sides of the decimal point, causing it to incorrectly reject integers and numbers like ".5". The corrected code below offers a more flexible solution.
import re
def validate_decimal(number_str):
pattern = r'^(\d+(\.\d*)?|\.\d+)$' # Matches integers and decimals
return bool(re.match(pattern, number_str))
print(validate_decimal("42")) # Integer
print(validate_decimal("3.14159")) # Decimal
print(validate_decimal(".5")) # Leading decimal
The corrected validate_decimal function uses a more flexible regex pattern: r'^(\d+(\.\d*)?|\.\d+)$'. This pattern correctly validates integers ("42"), decimals ("3.14159"), and numbers starting with a decimal point (".5"). It’s able to do this by using an OR operator (|) to match either an integer with an optional decimal part or a number that begins with a decimal. This approach ensures you don't accidentally reject valid numeric formats.
Real-world applications
These validation techniques are the building blocks for real-world applications, from validating user registration forms to cleaning messy datasets.
Validating user input in a registration form with isdigit()
In a registration form, you can use the isdigit() method to quickly confirm that an age input consists only of digits before checking if it falls within a valid range.
def validate_age(age_str):
if not age_str.isdigit():
return "Error: Age must contain only digits"
age = int(age_str)
if age < 18 or age > 120:
return "Error: Age must be between 18 and 120"
return f"Success: {age} is a valid age"
print(validate_age("25"))
print(validate_age("seventeen"))
print(validate_age("150"))
The validate_age function demonstrates a common two-step validation pattern. It first confirms the input string contains only digits using isdigit(). This initial check prevents the program from crashing when it later tries to convert the string to a number.
- If the string is purely digits, it's converted to an integer.
- The function then verifies the number falls within a logical range, between 18 and 120.
This layered approach ensures that you handle both data type and business logic rules effectively.
Cleaning numeric data from CSV files with try/except
When cleaning data from sources like CSV files, a try/except block is an effective way to handle entries that can't be converted to numbers without crashing your script.
def process_price_data(data_lines):
valid_prices = []
for line in data_lines:
if ',' not in line:
continue
product, price = line.split(',')
try:
valid_prices.append((product, float(price)))
except ValueError:
print(f"Skipping invalid price for {product}: {price}")
return valid_prices
data = ["apple,2.50", "banana,1.99", "orange,invalid", "grape,3.75"]
print(process_price_data(data))
The process_price_data function is designed to clean raw data by parsing each string into a product and its corresponding price. It uses a try/except block to safely handle conversions to decimal numbers with float(), which makes the process robust.
- The script won't crash when it encounters bad data, like the string
"invalid". - It isolates and reports the specific entries that fail conversion.
- It returns a clean list of tuples, such as
('apple', 2.50), that's structured for immediate use.
Get started with Replit
Turn these techniques into a real tool. Tell Replit Agent to “build a data cleaning script for CSVs” or “create a web-based loan calculator that validates all user inputs.”
Replit Agent writes the code, tests for errors, and deploys the app. Start building with Replit.
Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.
Create & deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.

.png)
.png)
.png)