如何在Python中检查字符串是否表示数值?

def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

上述方法可行,但似乎很笨拙。


如果您正在测试的内容来自用户输入,那么即使它表示int或float,它仍然是一个字符串。请参阅如何将输入读取为数字?用于转换输入,并询问用户输入,直到他们给出有效响应以确保输入在继续之前表示int或float(或其他要求)。


当前回答

TL;DR最佳解决方案是s.replace('.','',1).isdigit()

我做了一些比较不同方法的基准测试

def is_number_tryexcept(s):
    """ Returns True if string is a number. """
    try:
        float(s)
        return True
    except ValueError:
        return False
       
import re    
def is_number_regex(s):
    """ Returns True if string is a number. """
    if re.match("^\d+?\.\d+?$", s) is None:
        return s.isdigit()
    return True


def is_number_repl_isdigit(s):
    """ Returns True if string is a number. """
    return s.replace('.','',1).isdigit()

如果字符串不是数字,则except块非常慢。但更重要的是,try-except方法是正确处理科学符号的唯一方法。

funcs = [
          is_number_tryexcept, 
          is_number_regex,
          is_number_repl_isdigit
          ]

a_float = '.1234'

print('Float notation ".1234" is not supported by:')
for f in funcs:
    if not f(a_float):
        print('\t -', f.__name__)

以下项不支持浮点符号“.1234”:

is_number_regex编号科学1='1.000000e+50'科学2=“1e50”print('不支持科学符号“1.0000000e+50”:')对于函数中的f:如果不是f(科学1):打印('\t-',f.name)print('不支持科学符号“1e50”:')对于函数中的f:如果不是f(科学2):打印('\t-',f.name)

以下各项不支持科学符号“1.0000000e+50”:

is_number_regex编号is_number_repl_isdigit编号以下各项不支持科学符号“1e50”:is_number_regex编号is_number_repl_isdigit编号

编辑:基准结果

import timeit

test_cases = ['1.12345', '1.12.345', 'abc12345', '12345']
times_n = {f.__name__:[] for f in funcs}

for t in test_cases:
    for f in funcs:
        f = f.__name__
        times_n[f].append(min(timeit.Timer('%s(t)' %f, 
                      'from __main__ import %s, t' %f)
                              .repeat(repeat=3, number=1000000)))

测试了以下功能

from re import match as re_match
from re import compile as re_compile

def is_number_tryexcept(s):
    """ Returns True if string is a number. """
    try:
        float(s)
        return True
    except ValueError:
        return False

def is_number_regex(s):
    """ Returns True if string is a number. """
    if re_match("^\d+?\.\d+?$", s) is None:
        return s.isdigit()
    return True


comp = re_compile("^\d+?\.\d+?$")    

def compiled_regex(s):
    """ Returns True if string is a number. """
    if comp.match(s) is None:
        return s.isdigit()
    return True


def is_number_repl_isdigit(s):
    """ Returns True if string is a number. """
    return s.replace('.','',1).isdigit()

其他回答

试试这个。

 def is_number(var):
    try:
       if var == int(var):
            return True
    except Exception:
        return False

我认为您的解决方案很好,但有一个正确的正则表达式实现。

对于这些答案,似乎有很多正则表达式的仇恨,我认为这是不合理的,正则表达式可以相当干净、正确和快速。这真的取决于你想做什么。最初的问题是如何“检查字符串是否可以表示为数字(浮点数)”(根据你的标题)。在检查了数值/浮点值是否有效后,您可能希望使用它,在这种情况下,try/except非常有意义。但是,如果出于某种原因,您只想验证字符串是数字,那么正则表达式也可以正常工作,但很难得到正确的结果。例如,我认为到目前为止,大多数正则表达式的答案都不能正确解析没有整数部分(如“.7”)的字符串,就python而言,整数部分是一个浮点数。在不需要小数部分的单个正则表达式中检查这一点有点困难。我包含了两个正则表达式来显示这一点。

它确实提出了一个有趣的问题,即“数字”是什么。您是否包含“inf”,它在python中作为浮点数有效?或者您是否包含“数字”但可能无法在python中表示的数字(例如大于float max的数字)。

解析数字的方式也存在歧义。例如,“--20”呢?这是一个“数字”吗?这是代表“20”的合法方式吗?Python将允许您执行“var=--20”并将其设置为20(尽管实际上这是因为它将其作为表达式处理),但float(“--20”)不起作用。

无论如何,在没有更多信息的情况下,这里有一个正则表达式,我相信它涵盖了python解析它们时的所有int和float。

# Doesn't properly handle floats missing the integer part, such as ".7"
SIMPLE_FLOAT_REGEXP = re.compile(r'^[-+]?[0-9]+\.?[0-9]+([eE][-+]?[0-9]+)?$')
# Example "-12.34E+56"      # sign (-)
                            #     integer (12)
                            #           mantissa (34)
                            #                    exponent (E+56)

# Should handle all floats
FLOAT_REGEXP = re.compile(r'^[-+]?([0-9]+|[0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?$')
# Example "-12.34E+56"      # sign (-)
                            #     integer (12)
                            #           OR
                            #             int/mantissa (12.34)
                            #                            exponent (E+56)

def is_float(str):
  return True if FLOAT_REGEXP.match(str) else False

一些示例测试值:

True  <- +42
True  <- +42.42
False <- +42.42.22
True  <- +42.42e22
True  <- +42.42E-22
False <- +42.42e-22.8
True  <- .42
False <- 42nope

在@ron reiter的回答中运行基准测试代码表明,这个正则表达式实际上比普通正则表达式快,并且在处理错误值方面比异常快得多,这是有道理的。结果:

check_regexp with good floats: 18.001921
check_regexp with bad floats: 17.861423
check_regexp with strings: 17.558862
check_correct_regexp with good floats: 11.04428
check_correct_regexp with bad floats: 8.71211
check_correct_regexp with strings: 8.144161
check_replace with good floats: 6.020597
check_replace with bad floats: 5.343049
check_replace with strings: 5.091642
check_exception with good floats: 5.201605
check_exception with bad floats: 23.921864
check_exception with strings: 23.755481

我做了一些速度测试。让我们假设,如果字符串可能是一个数字,则try/except策略是最快的。如果字符串不可能是数字,并且您对整数检查感兴趣,则值得进行一些测试(isdigit加上标题“-”)。如果您有兴趣检查浮点数,则必须使用try/except代码而不进行转义。

仅对于非负(无符号)整数,请使用isdigit():

>>> a = "03523"
>>> a.isdigit()
True
>>> b = "963spam"
>>> b.isdigit()
False

isdigit()文档:Python2,Python3

对于Python 2 Unicode字符串:isnumeric()。

def is_float(s):
    if s is None:
        return False

    if len(s) == 0:
        return False

    digits_count = 0
    dots_count = 0
    signs_count = 0

    for c in s:
        if '0' <= c <= '9':
            digits_count += 1
        elif c == '.':
            dots_count += 1
        elif c == '-' or c == '+':
            signs_count += 1
        else:
            return False

    if digits_count == 0:
        return False

    if dots_count > 1:
        return False

    if signs_count > 1:
        return False

    return True