如何在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()

其他回答

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()

我知道我参加晚会迟到了,但我想出了一个不在这里的解决方案:此解决方案遵循Python中的EAFP原则

def get_number_from_string(value):
    try:
        int_value = int(value)
        return int_value

    except ValueError:
        return float(value)

说明:

如果字符串中的值是一个浮点数,并且我首先尝试将其解析为一个int,那么它将抛出一个ValueError。因此,我捕捉到该错误,并将该值解析为float和return。

这不仅是丑陋和缓慢的,而且显得笨拙。

这可能需要一些时间来适应,但这是一种蟒蛇式的方式。正如已经指出的那样,替代方案更糟糕。但这样做还有一个好处:多态性。

duck类型背后的核心思想是“如果它像鸭子一样走路和说话,那么它就是鸭子。”如果您决定需要对字符串进行子类化,这样您就可以更改确定某个对象是否可以转换为float的方式,该怎么办?或者如果你决定完全测试其他对象呢?您可以在不必更改上述代码的情况下执行这些操作。

其他语言通过使用接口来解决这些问题。我将保存对哪个解决方案更适合另一个线程的分析。不过,重点是python显然是在公式中的鸭子类型方面,如果你打算用python进行大量编程,你可能必须习惯这样的语法(但这并不意味着你当然要喜欢它)。

还有一点您可能需要考虑:与许多其他语言相比,Python在抛出和捕获异常方面非常快(例如,比.Net快30倍)。见鬼,语言本身甚至抛出异常来传达非异常的正常程序条件(每次使用for循环时)。因此,在您注意到一个重大问题之前,我不会太担心这段代码的性能方面。

很抱歉,Zombie发布了一篇帖子-只是想让代码更加完整。。。

# is_number() function - Uses re = regex library
# Should handle all normal and complex numbers
# Does not accept trailing spaces. 
# Note: accepts both engineering "j" and math "i" but only the imaginary part "+bi" of a complex number a+bi
# Also accepts inf or NaN
# Thanks to the earlier responders for most the regex fu

import re

ISNUM_REGEXP = re.compile(r'^[-+]?([0-9]+|[0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?[ij]?$')

def is_number(str):
#change order if you have a lot of NaN or inf to parse
    if ISNUM_REGEXP.match(str) or str == "NaN" or str == "inf": 
        return True 
    else:
        return False
# A couple test numbers
# +42.42e-42j
# -42.42E+42i

print('Is it a number?', is_number(input('Gimme any number: ')))

给我任何号码:+42.42e-42j

是数字吗?真的

我正在研究一个问题,这个问题使我想到了这个主题,即如何以最直观的方式将一组数据转换为字符串和数字。在阅读原始代码后,我意识到我需要的东西在两个方面有所不同:

1-如果字符串表示整数,我希望得到整数结果

2-我想要一个数字或字符串结果粘贴到数据结构中

所以我修改了原始代码来生成这个派生代码:

def string_or_number(s):
    try:
        z = int(s)
        return z
    except ValueError:
        try:
            z = float(s)
            return z
        except ValueError:
            return s