2010-02-11 46 views
1

我尝试了几种方法,我只关心性能,而不是正确性。我注意到基于正则表达式的实现比使用类型强制的实现要慢3-4倍。是否有另一种更有效的方式来做到这一点?Python:识别数字字符串?

def IsNumber(x): 
    try: 
     _ = float(x) 
    except ValueError: 
     return False 
    return True 

def IsNumber2(x): 
    import re 
    if re.match("^\d*.?\d*$", x) == None: 
     return False 
    return True 

谢谢!

+0

第一种方法是正确且有用的。第二个是间接的,有多个微妙的错误。 –

+0

@Mike Graham:您的评论听起来像是一个答案。请删除评论,发布答案,然后我们可以正确地对其进行修改。 –

+0

你的正则表达式中的另一个错误:你需要逃避那个。之前 ?除非你想123z45被视为“一个数字”。 –

回答

6

首先,他们没有做同样的事情。例如,浮动可以被指定为“1e3”,并且float()将接受它。这也不是coercion,而是转换。其次,不要在IsNumber2中导入re,尤其是如果你试图在timeit中使用它。在函数之外进行导入。

最后,float()更快并不让我感到惊讶。这是一个用C编写的专用程序,用于特定目的,而正则表达式必须转换为解释的形式。

是您的第一个版本,使用float(),速度够快吗?它应该是,而且我不知道有更好的方法来在Python中做同样的事情。

+0

第一个版本足够快我想我只是好奇而已。谢谢! – fsm

2

不是。强制是公认的做法。

+0

是的,你的方法看起来相当不错。我并不惊讶正则表达式方法更慢。 (有一件事是它在函数内部导入)。 –

+0

@Justin:第二次导入're'只是复制'sys.modules'引用的问题。缓慢的部分是每次编译正则表达式。 –

+0

导入语句确实执行了一些不希望的锁定。让它们远离功能会更快。 – joeforker

0

你可能会尝试编译你的正则表达式,但我想它会更慢。另外,如果你想知道你的字符串是否是一个数字,因为你要对它进行计算,那么无论如何你都必须强迫它。

+0

编译只有很小的影响,它们被缓存。 http://stackoverflow.com/questions/452104/is-it-worth-using-pythons-re-compile – 2010-02-11 22:26:37

2

答案很大程度上取决于'数字串'的含义。如果数字字符串的定义是“任何可以接受的东西”,那么很难改进try-except方法。

但请记住,浮动可能比您想要的更加自由:在大多数机器上,它会接受代表无穷大和nans的字符串。例如,在我的机器上,它接受'nan(dead!$#parrot)'。它也将接受前导空白和尾随空白。取决于您的应用程序,您可能希望排除浮点数的指数表示。在这些情况下,使用正则表达式是有道理的。为了排除infinities和nans,使用try-except方法可能会更快,然后使用math.isnan和math.isinf来检查转换结果。

为数字字符串编写正确的正则表达式是一个令人惊讶的容易出错的任务。例如,您的IsNumber2函数接受字符串'.'。您可以在十进制模块源中找到经过测试的数字字符串正则表达式版本。这是(有一些小修改):

_parser = re.compile(r"""  # A numeric string consists of: 
    (?P<sign>[-+])?    # an optional sign, followed by either... 
    (
     (?=\d|\.\d)    # ...a number (with at least one digit) 
     (?P<int>\d*)    # having a (possibly empty) integer part 
     (\.(?P<frac>\d*))?  # followed by an optional fractional part 
     (E(?P<exp>[-+]?\d+))? # followed by an optional exponent, or... 
    | 
     Inf(inity)?    # ...an infinity, or... 
    | 
     (?P<signal>s)?   # ...an (optionally signaling) 
     NaN      # NaN 
     (?P<diag>\d*)   # with (possibly empty) diagnostic info. 
    ) 
    \Z 
""", re.VERBOSE | re.IGNORECASE | re.UNICODE).match 

这几乎场比赛正是浮接受,除了开头和结尾的空白和NaN的一些细微的差别(多余的“S”的信号NaN,和诊断信息)。当我需要一个数字正则表达式时,我通常从这个开始,编辑出我不需要的位。

N.B.这是可以想象浮点数可能比正则表达式慢,因为它不仅要解析字符串,还要把它变成一个浮点数,这是一个相当复杂的计算;但如果是这样,它仍然会是一个惊喜。