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

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

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


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


当前回答

因此,将所有这些放在一起,检查Nan、无穷大和复数(看起来它们是用j指定的,而不是i,即1+2j),结果是:

def is_number(s):
    try:
        n=str(float(s))
        if n == "nan" or n=="inf" or n=="-inf" : return False
    except ValueError:
        try:
            complex(s) # for complex
        except ValueError:
            return False
    return True

其他回答

我想看看哪种方法最快。总的来说,check_replace函数给出了最佳和最一致的结果。check_exception函数给出了最快的结果,但前提是没有触发异常——这意味着它的代码是最有效的,但抛出异常的开销非常大。

请注意,检查成功的强制转换是唯一准确的方法,例如,这与check_exception一起工作,但其他两个测试函数将为有效的float返回False:

huge_number = float('1e+100')

以下是基准代码:

import time, re, random, string

ITERATIONS = 10000000

class Timer:    
    def __enter__(self):
        self.start = time.clock()
        return self
    def __exit__(self, *args):
        self.end = time.clock()
        self.interval = self.end - self.start

def check_regexp(x):
    return re.compile("^\d*\.?\d*$").match(x) is not None

def check_replace(x):
    return x.replace('.','',1).isdigit()

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

to_check = [check_regexp, check_replace, check_exception]

print('preparing data...')
good_numbers = [
    str(random.random() / random.random()) 
    for x in range(ITERATIONS)]

bad_numbers = ['.' + x for x in good_numbers]

strings = [
    ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(random.randint(1,10)))
    for x in range(ITERATIONS)]

print('running test...')
for func in to_check:
    with Timer() as t:
        for x in good_numbers:
            res = func(x)
    print('%s with good floats: %s' % (func.__name__, t.interval))
    with Timer() as t:
        for x in bad_numbers:
            res = func(x)
    print('%s with bad floats: %s' % (func.__name__, t.interval))
    with Timer() as t:
        for x in strings:
            res = func(x)
    print('%s with strings: %s' % (func.__name__, t.interval))

以下是2017年MacBook Pro 13上Python 2.7.10的结果:

check_regexp with good floats: 12.688639
check_regexp with bad floats: 11.624862
check_regexp with strings: 11.349414
check_replace with good floats: 4.419841
check_replace with bad floats: 4.294909
check_replace with strings: 4.086358
check_exception with good floats: 3.276668
check_exception with bad floats: 13.843092
check_exception with strings: 15.786169

以下是2017年MacBook Pro 13上Python 3.6.5的结果:

check_regexp with good floats: 13.472906000000009
check_regexp with bad floats: 12.977665000000016
check_regexp with strings: 12.417542999999995
check_replace with good floats: 6.011045999999993
check_replace with bad floats: 4.849356
check_replace with strings: 4.282754000000011
check_exception with good floats: 6.039081999999979
check_exception with bad floats: 9.322753000000006
check_exception with strings: 9.952595000000002

以下是2017年MacBook Pro 13上PyPy 2.7.13的结果:

check_regexp with good floats: 2.693217
check_regexp with bad floats: 2.744819
check_regexp with strings: 2.532414
check_replace with good floats: 0.604367
check_replace with bad floats: 0.538169
check_replace with strings: 0.598664
check_exception with good floats: 1.944103
check_exception with bad floats: 2.449182
check_exception with strings: 2.200056

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

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

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

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

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

str.inumeric()

如果字符串中的所有字符都是数字字符,则返回True,并且至少有一个字符,否则为False。数字字符包括数字字符Unicode数值属性,例如U+2155,VULGAR FRACTION ONE第五。形式上,数字字符是具有属性值的字符Numeric_Type=数字,Numeric_Type=十进制或Numeric_Type=数字。

str.isdecimal()

如果字符串中的所有字符都是十进制字符,并且至少有一个字符,否则为False。十进制字符是可用于在基数10中形成数字的那些,阿拉伯数字零。形式上,十进制字符是一个字符在Unicode通用类别“Nd”中。

两者都适用于Python 3.0中的字符串类型。

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

您可以使用Unicode字符串,它们有一种方法可以满足您的需要:

>>> s = u"345"
>>> s.isnumeric()
True

Or:

>>> s = "345"
>>> u = unicode(s)
>>> u.isnumeric()
True

http://www.tutorialspoint.com/python/string_isnumeric.htm

http://docs.python.org/2/howto/unicode.html