如何检查字符串是否为数字(浮点数)?

问题描述 投票:1401回答:33

检查字符串是否可以在Python中表示为数字的最佳方法是什么?

我目前拥有的功能是:

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

这不仅是丑陋而且缓慢,似乎很笨重。但是我没有找到更好的方法,因为在主函数中调用float更糟糕。

python casting floating-point type-conversion
33个回答
634
投票

其中,不仅是丑陋而且缓慢

我两个都有争议。

正则表达式或其他字符串解析方法会更加丑陋和缓慢。

我不确定任何事情都可能比上面更快。它调用函数并返回。 Try / Catch不会引入太多开销,因为最常见的异常是在没有大量搜索堆栈帧的情况下捕获的。

问题是任何数字转换函数都有两种结果

  • 如果数字有效,则为数字
  • 状态代码(例如,通过errno)或异常以显示无法解析有效数字。

C(作为一个例子)以多种方式解决这个问题。 Python明确而明确地阐述了它。

我认为你这样做的代码是完美的。


15
投票

对于非数字的字符串,try: except:实际上比正则表达式慢。对于有效数字的字符串,正则表达式较慢。因此,适当的方法取决于您的输入。

如果您发现自己处于性能绑定中,则可以使用名为fastnumbers的新第三方模块,该模块提供名为isfloat的函数。完全披露,我是作者。我已将结果包含在下面的时间中。


from __future__ import print_function
import timeit

prep_base = '''\
x = 'invalid'
y = '5402'
z = '4.754e3'
'''

prep_try_method = '''\
def is_number_try(val):
    try:
        float(val)
        return True
    except ValueError:
        return False

'''

prep_re_method = '''\
import re
float_match = re.compile(r'[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?$').match
def is_number_re(val):
    return bool(float_match(val))

'''

fn_method = '''\
from fastnumbers import isfloat

'''

print('Try with non-number strings', timeit.timeit('is_number_try(x)',
    prep_base + prep_try_method), 'seconds')
print('Try with integer strings', timeit.timeit('is_number_try(y)',
    prep_base + prep_try_method), 'seconds')
print('Try with float strings', timeit.timeit('is_number_try(z)',
    prep_base + prep_try_method), 'seconds')
print()
print('Regex with non-number strings', timeit.timeit('is_number_re(x)',
    prep_base + prep_re_method), 'seconds')
print('Regex with integer strings', timeit.timeit('is_number_re(y)',
    prep_base + prep_re_method), 'seconds')
print('Regex with float strings', timeit.timeit('is_number_re(z)',
    prep_base + prep_re_method), 'seconds')
print()
print('fastnumbers with non-number strings', timeit.timeit('isfloat(x)',
    prep_base + 'from fastnumbers import isfloat'), 'seconds')
print('fastnumbers with integer strings', timeit.timeit('isfloat(y)',
    prep_base + 'from fastnumbers import isfloat'), 'seconds')
print('fastnumbers with float strings', timeit.timeit('isfloat(z)',
    prep_base + 'from fastnumbers import isfloat'), 'seconds')
print()

Try with non-number strings 2.39108395576 seconds
Try with integer strings 0.375686168671 seconds
Try with float strings 0.369210958481 seconds

Regex with non-number strings 0.748660802841 seconds
Regex with integer strings 1.02021503448 seconds
Regex with float strings 1.08564686775 seconds

fastnumbers with non-number strings 0.174362897873 seconds
fastnumbers with integer strings 0.179651021957 seconds
fastnumbers with float strings 0.20222902298 seconds

如你看到的

  • try: except:数字输入速度很快,但输入无效的速度很慢
  • 当输入无效时,正则表达式非常有效
  • fastnumbers在这两种情况下都获胜

12
投票

我知道这个特别古老,但我会添加一个答案,我认为这些答案涵盖了最高投票答案中缺少的信息,对于任何发现这一点的人来说都是非常有价值的:

对于以下每种方法,如果需要接受任何输入,请将它们与计数相连。 (假设我们使用整数的声音定义而不是0-255等)

x.isdigit()适用于检查x是否为整数。

x.replace('-','').isdigit()适用于检查x是否为负数。(签到第一个位置)

x.replace('.','').isdigit()适用于检查x是否为小数。

x.replace(':','').isdigit()适用于检查x是否为比率。

x.replace('/','',1).isdigit()适用于检查x是否为分数。


11
投票

转换为float并捕获ValueError可能是最快的方法,因为float()专门用于此。任何需要字符串解析(正则表达式等)的东西都可能会因为没有针对此操作进行调整而变慢。我的0.02美元。


11
投票

你可以使用Unicode字符串,他们有一个方法可以做你想要的:

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

要么:

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

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

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


9
投票

这个答案提供了一步一步的指南,其中有一些函数用例来查找字符串:

  • 正整数
  • 正/负 - 整数/浮点数
  • 如何在检查号码时丢弃“NaN”(不是数字)字符串?

Check if string is positive integer

您可以使用str.isdigit()来检查给定的字符串是否为正整数。

样本结果:

# For digit
>>> '1'.isdigit()
True
>>> '1'.isalpha()
False

Check for string as positive/negative - integer/float

如果字符串是负数或浮点数,str.isdigit()返回False。例如:

# returns `False` for float
>>> '123.3'.isdigit()
False
# returns `False` for negative number
>>> '-123'.isdigit()
False

如果你还想检查负整数和float,那么你可以编写一个自定义函数来检查它:

def is_number(n):
    try:
        float(n)   # Type-casting the string to `float`.
                   # If string is not a valid `float`, 
                   # it'll raise `ValueError` exception
    except ValueError:
        return False
    return True

样品运行:

>>> is_number('123')    # positive integer number
True

>>> is_number('123.4')  # positive float number
True

>>> is_number('-123')   # negative integer number
True

>>> is_number('-123.4') # negative `float` number
True

>>> is_number('abc')    # `False` for "some random" string
False

Discard "NaN" (not a number) strings while checking for number

上面的函数将为“NAN”(非数字)字符串返回True,因为对于Python,它是有效的float,表示它不是数字。例如:

>>> is_number('NaN')
True

为了检查数字是否为“NaN”,您可以使用math.isnan()作为:

>>> import math
>>> nan_num = float('nan')

>>> math.isnan(nan_num)
True

或者,如果您不想导入其他库来检查这一点,那么您可以通过使用==将其与自身进行比较来检查它。当False float与自身进行比较时,Python返回nan。例如:

# `nan_num` variable is taken from above example
>>> nan_num == nan_num
False

因此,上面的函数is_number可以更新为False返回"NaN"

def is_number(n):
    is_number = True
    try:
        num = float(n)
        # check for "nan" floats
        is_number = num == num   # or use `math.isnan(num)`
    except ValueError:
        is_number = False
    return is_number

样品运行:

>>> is_number('Nan')   # not a number "Nan" string
False

>>> is_number('nan')   # not a number string "nan" with all lower cased
False

>>> is_number('123')   # positive integer
True

>>> is_number('-123')  # negative integer
True

>>> is_number('-1.12') # negative `float`
True

>>> is_number('abc')   # "some random" string
False

PS:每个检查的每个操作取决于数字的类型带来额外的开销。选择符合您要求的is_number功能版本。


9
投票

我想看看哪种方法最快。总的来说,最好和最一致的结果是由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

7
投票

所以把它们放在一起,检查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

4
投票

我做了一些速度测试。让我们说如果字符串可能是一个数字,那么try / except策略是最快的。如果字符串不太可能是一个数字并且您对Integer检查感兴趣,那么值得做一些测试(isdigit plus heading ' - ')。如果您有兴趣检查浮点数,则必须使用try / except代码whitout转义。


4
投票

我需要确定一个字符串是否转换为基本类型(float,int,str,bool)。在互联网上找不到任何东西后我创建了这个:

def str_to_type (s):
    """ Get possible cast type for a string

    Parameters
    ----------
    s : string

    Returns
    -------
    float,int,str,bool : type
        Depending on what it can be cast to

    """    
    try:                
        f = float(s)        
        if "." not in s:
            return int
        return float
    except ValueError:
        value = s.upper()
        if value == "TRUE" or value == "FALSE":
            return bool
        return type(s)

str_to_type("true") # bool
str_to_type("6.0") # float
str_to_type("6") # int
str_to_type("6abc") # str
str_to_type(u"6abc") # unicode       

您可以捕获类型并使用它

s = "6.0"
type_ = str_to_type(s) # float
f = type_(s) 

4
投票

输入可能如下:

a="50" b=50 c=50.1 d="50.1"


1-通用输入:

这个功能的输入可以是一切!

查找给定变量是否为数字。数字字符串由可选符号,任意数量的数字,可选的小数部分和可选的指数部分组成。因此+ 0123.45e6是有效的数值。不允许使用十六进制(例如0xf4c3b00c)和二进制(例如0b10100111001)表示法。

is_numeric函数

import ast
import numbers              
def is_numeric(obj):
    if isinstance(obj, numbers.Number):
        return True
    elif isinstance(obj, str):
        nodes = list(ast.walk(ast.parse(obj)))[1:]
        if not isinstance(nodes[0], ast.Expr):
            return False
        if not isinstance(nodes[-1], ast.Num):
            return False
        nodes = nodes[1:-1]
        for i in range(len(nodes)):
            #if used + or - in digit :
            if i % 2 == 0:
                if not isinstance(nodes[i], ast.UnaryOp):
                    return False
            else:
                if not isinstance(nodes[i], (ast.USub, ast.UAdd)):
                    return False
        return True
    else:
        return False

测试:

>>> is_numeric("54")
True
>>> is_numeric("54.545")
True
>>> is_numeric("0x45")
True

is_float函数

查找给定变量是否为float。浮点字符串由可选符号,任意数量的数字组成,......

import ast

def is_float(obj):
    if isinstance(obj, float):
        return True
    if isinstance(obj, int):
        return False
    elif isinstance(obj, str):
        nodes = list(ast.walk(ast.parse(obj)))[1:]
        if not isinstance(nodes[0], ast.Expr):
            return False
        if not isinstance(nodes[-1], ast.Num):
            return False
        if not isinstance(nodes[-1].n, float):
            return False
        nodes = nodes[1:-1]
        for i in range(len(nodes)):
            if i % 2 == 0:
                if not isinstance(nodes[i], ast.UnaryOp):
                    return False
            else:
                if not isinstance(nodes[i], (ast.USub, ast.UAdd)):
                    return False
        return True
    else:
        return False

测试:

>>> is_float("5.4")
True
>>> is_float("5")
False
>>> is_float(5)
False
>>> is_float("5")
False
>>> is_float("+5.4")
True

什么是ast


2-如果您确信变量内容是String:

使用str.isdigit()方法

>>> a=454
>>> a.isdigit()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'isdigit'
>>> a="454"
>>> a.isdigit()
True

3数字输入:

检测int值:

>>> isinstance("54", int)
False
>>> isinstance(54, int)
True
>>> 

检测浮动:

>>> isinstance("45.1", float)
False
>>> isinstance(45.1, float)
True

1461
投票

如果您正在寻找解析(正,无符号)整数而不是浮点数,您可以将isdigit()函数用于字符串对象。

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

String Methods - isdigit()

在Unicode字符串上也有一些东西,我对Unicode - Is decimal/decimal不太熟悉


3
投票

RyanN建议

如果要为NaN和Inf返回False,请将行更改为x = float(s); return(x == x)和(x - 1!= x)。对于除Inf和NaN之外的所有浮点数,这应该返回True

但这不太有用,因为对于足够大的浮点数,x-1 == x返回true。例如,2.0**54 - 1 == 2.0**54


1
投票

我也使用了你提到的功能,但很快我注意到字符串为“Nan”,“Inf”,它的变化被认为是数字。所以我建议你改进你的函数版本,这将在这些类型的输入上返回false并且不会失败“1e3”变体:

def is_float(text):
    try:
        float(text)
        # check for nan/infinity etc.
        if text.isalpha():
            return False
        return True
    except ValueError:
        return False

1
投票
import re
def is_number(num):
    pattern = re.compile(r'^[-+]?[-0-9]\d*\.\d*|[-+]?\.?[0-9]\d*$')
    result = pattern.match(num)
    if result:
        return True
    else:
        return False


​>>>: is_number('1')
True

>>>: is_number('111')
True

>>>: is_number('11.1')
True

>>>: is_number('-11.1')
True

>>>: is_number('inf')
False

>>>: is_number('-inf')
False

1
投票

此代码处理指数,浮点数和整数,而不使用正则表达式。

return True if str1.lstrip('-').replace('.','',1).isdigit() or float(str1) else False

1
投票

我认为您的解决方案很好。

话虽如此,对于这些答案有很多正面的仇恨,我认为这些答案是不合理的,正则表达式可以合理清洁,正确和快速。这真的取决于你想要做什么。最初的问题是你如何“检查字符串是否可以表示为数字(浮点数)”(根据你的标题)。一旦你检查它是否有效,大概你会想要使用数值/浮点值,在这种情况下你的try / except很有意义。但是,如果由于某种原因,你只想验证一个字符串是一个数字,那么一个正则表达式也可以正常工作,但很难得到正确的。到目前为止,我认为大多数正则表达式的答案,例如,没有正确解析没有整数部分的字符串(例如“.7”),就p​​ython而言,它是一个浮点数。在单个正则表达式中检查是否有点棘手,其中不需要小数部分。我已经包含了两个正则表达式来展示这个。

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

你解析数字的方式也很模糊。例如,“ - 20”怎么办?这是一个“数字”吗?这是代表“20”的合法方式吗? Python会让你做“var = --20”并将其设置为20(虽然这是因为它将它视为表达式),但float(“ - 20”)不起作用。

无论如何,没有更多的信息,这是一个正则表达式,我相信涵盖所有的int和浮动python解析它们。

# 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

0
投票

这是我做这件事的简单方法。假设我正在循环一些字符串,我想将它们添加到数组中,如果它们变成数字的话。

try:
    myvar.append( float(string_to_check) )
except:
    continue

如果结果是一个数字,请将myvar.apppend替换为您要对字符串执行的任何操作。我们的想法是尝试使用float()操作并使用返回的错误来确定字符串是否为数字。


0
投票

您可以通过返回比True和False更有用的值来以有用的方式概括异常技术。例如,此函数将引号括在字符串中但仅留下数字。这正是我需要一个快速和脏的过滤器来为R做一些变量定义。

import sys

def fix_quotes(s):
    try:
        float(s)
        return s
    except ValueError:
        return '"{0}"'.format(s)

for line in sys.stdin:
    input = line.split()
    print input[0], '<- c(', ','.join(fix_quotes(c) for c in input[1:]), ')'

0
投票

我正在研究导致我进入这个线程的问题,即如何以最直观的方式将数据集合转换为字符串和数字。我在阅读原始代码后意识到我需要的东西在两个方面有所不同:

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

0
投票

试试这个。

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

-1
投票

使用以下它处理所有情况: -

import re
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '2.3') 
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '2.')
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '.3')
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '2.3sd')
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '2.3')

117
投票

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

我做了一些benchmarks比较不同的方法

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

import re    
def is_number_regex(s):
    """ Returns True is 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 is string is a number. """
    return s.replace('.','',1).isdigit()

如果字符串不是数字,则except-block非常慢。但更重要的是,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

scientific1 = '1.000000e+50'
scientific2 = '1e50'


print('Scientific notation "1.000000e+50" is not supported by:')
for f in funcs:
    if not f(scientific1):
        print('\t -', f.__name__)




print('Scientific notation "1e50" is not supported by:')
for f in funcs:
    if not f(scientific2):
        print('\t -', f.__name__)

不支持科学记数法“1.000000e + 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 is string is a number. """
    try:
        float(s)
        return True
    except ValueError:
        return False

def is_number_regex(s):
    """ Returns True is 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 is string is a number. """
    if comp.match(s) is None:
        return s.isdigit()
    return True


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

enter image description here


-1
投票

我有一个类似的问题。我想要将一个字符串列表转换为浮点数,而不是定义一个isNumber函数,这在高级术语中将是:

[ float(s) for s in list if isFloat(s)]

我们无法将浮点数与isFloat(s)函数分开:这两个结果应该由同一个函数返回。此外,如果float(s)失败,整个过程将失败,而不是仅忽略有缺陷的元素。另外,“0”是有效数字,应该包含在列表中。过滤掉坏元素时,请确保不排除0。

因此,必须以某种方式修改上述理解为:

  • 如果列表中的任何元素无法转换,请忽略它并且不抛出异常
  • 避免为每个元素多次调用float(一个用于转换,另一个用于测试)
  • 如果转换后的值为0,则它​​仍应出现在最终列表中

我提出了一个灵感来自Nullable数值类型C#的解决方案。这些类型在内部由具有数值的结构表示,并添加一个布尔值,指示该值是否有效:

def tryParseFloat(s):
    try:
        return(float(s), True)
    except:
        return(None, False)

tupleList = [tryParseFloat(x) for x in list]
floats = [v for v,b in tupleList if b]

67
投票

您可能需要考虑一个例外:字符串'NaN'

如果你想让is_number为'NaN'返回FALSE,那么这段代码将不起作用,因为Python将它转换为一个不是数字的数字的表示(谈论身份问题):

>>> float('NaN')
nan

否则,我实际上应该感谢你现在广泛使用的代码片段。 :)

G。


53
投票

这个怎么样:

'3.14'.replace('.','',1).isdigit()

只有在有'或'的情况下才会返回true。在数字串中。

'3.14.5'.replace('.','',1).isdigit()

将返回false

编辑:刚看到另一条评论...为其他案例添加.replace(badstuff,'',maxnum_badstuff)可以完成。如果你传递盐而不是任意调味品(参考:xkcd#974),这样做会很好:P


39
投票

Alfe指出您不需要单独检查浮动,因为复杂处理两者:

def is_number(s):
    try:
        complex(s) # for int, long, float and complex
    except ValueError:
        return False

    return True

之前说过:在一些罕见的情况下,您可能还需要检查复数(例如1 + 2i),这不能用浮点数表示:

def is_number(s):
    try:
        float(s) # for int, long and float
    except ValueError:
        try:
            complex(s) # for complex
        except ValueError:
            return False

    return True

37
投票

这不仅是丑陋而且缓慢,似乎很笨重。

这可能需要一些时间来习惯,但这是做到这一点的pythonic方式。正如已经指出的那样,替代方案更糟糕。但是以这种方式做事还有另一个好处:多态性。

鸭子打字背后的核心理念是“如果它像鸭子一样走路和说话,那么它就是一只鸭子。”如果您决定需要子类化字符串以便可以更改确定是否可以将某些内容转换为浮点数的方式,该怎么办?或者如果您决定完全测试其他对象怎么办?您无需更改上述代码即可完成这些操作。

其他语言通过使用接口解决了这些问题。我将保存分析哪个解决方案更适合另一个线程。但问题是,python肯定是在等式的鸭子打字方面,如果你打算用Python做很多编程,你可能不得不习惯这样的语法(但这并不意味着你必须喜欢它当然)。

您可能需要考虑的另一件事是:与许多其他语言相比,Python在抛出和捕获异常方面相当快(例如,比.Net快30倍)。哎呀,语言本身甚至会抛出异常来传达非常规的正常程序条件(每次使用for循环)。因此,在您发现重大问题之前,我不会过多担心此代码的性能方面。


22
投票

对于int使用此:

>>> "1221323".isdigit()
True

但是对于float我们需要一些技巧;-)。每个浮点数都有一点......

>>> "12.34".isdigit()
False
>>> "12.34".replace('.','',1).isdigit()
True
>>> "12.3.4".replace('.','',1).isdigit()
False

同样对于负数,只需添加lstrip()

>>> '-12'.lstrip('-')
'12'

现在我们得到一个通用的方式:

>>> '-12.34'.lstrip('-').replace('.','',1).isdigit()
True
>>> '.-234'.lstrip('-').replace('.','',1).isdigit()
False

15
投票

只是模仿C#

在C#中,有两个不同的函数来处理标量值的解析:

  • Float.Parse()
  • Float.TryParse()

float.parse():

def parse(string):
    try:
        return float(string)
    except Exception:
        throw TypeError

注意:如果您想知道为什么我将异常更改为TypeError,here's the documentation

float.try_parse():

def try_parse(string, fail=None):
    try:
        return float(string)
    except Exception:
        return fail;

注意:您不希望返回布尔值'False',因为它仍然是值类型。没有比这更好,因为它表明失败。当然,如果您想要不同的东西,可以将fail参数更改为您想要的任何内容。

要扩展float以包含'parse()'和'try_parse()',您需要monkeypatch'float'类来添加这些方法。

如果您想要尊重预先存在的函数,代码应该是这样的:

def monkey_patch():
    if(!hasattr(float, 'parse')):
        float.parse = parse
    if(!hasattr(float, 'try_parse')):
        float.try_parse = try_parse

SideNote:我个人更喜欢称之为Monkey Punching,因为当我这样做时,感觉就像是在滥用语言而是YMMV。

用法:

float.parse('giggity') // throws TypeException
float.parse('54.3') // returns the scalar value 54.3
float.tryParse('twank') // returns None
float.tryParse('32.2') // returns the scalar value 32.2

伟大的Sage Pythonas向教廷Sharpisus说:“你能做的任何事情我都能做得更好;我能做比你更好的事情。”

© www.soinside.com 2019 - 2024. All rights reserved.