2010-02-11 45 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.這是可以想象浮點數可能比正則表達式慢,因爲它不僅要解析字符串,還要把它變成一個浮點數,這是一個相當複雜的計算;但如果是這樣,它仍然會是一個驚喜。