Python: идентификация числовой строки? - PullRequest
1 голос
/ 12 февраля 2010

Я испробовал несколько подходов, меня действительно интересует только производительность, а не корректность. Я заметил, что реализация на основе регулярных выражений примерно в 3-4 раза медленнее, чем та, которая использует приведение типов. Есть ли другой, более эффективный способ сделать это?

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

Спасибо! * * 1004

Ответы [ 4 ]

6 голосов
/ 12 февраля 2010

Прежде всего, они не делают то же самое. Например, число с плавающей запятой можно указать как "1e3", и float () примет это Это также не принуждение , а преобразование.

Во-вторых, не импортируйте re в IsNumber2, особенно если вы пытаетесь использовать его с timeit. Выполните импорт вне функции.

Наконец, меня не удивляет, что float () работает быстрее. Это специальная подпрограмма, написанная на C для очень конкретной цели, в то время как регулярное выражение должно быть преобразовано в интерпретируемую форму.

Ваша первая версия, которая использует float (), достаточно быстрая? Так и должно быть, и я не знаю лучшего способа сделать то же самое в Python.

2 голосов
/ 12 февраля 2010

Ответ во многом зависит от того, что вы подразумеваете под «числовой строкой». Если вы определили числовую строку как «все, что может принимать float», то трудно улучшить метод try-exc.

Но имейте в виду, что float может быть более либеральным, чем вы хотите: на большинстве машин он принимает строки, представляющие бесконечность и nans. На моей машине он принимает 'nan(dead!$#parrot)', например. Он также будет принимать начальные и конечные пробелы. И в зависимости от вашего приложения вы можете исключить экспоненциальное представление чисел с плавающей точкой. В этих случаях использование регулярных выражений имело бы смысл. Чтобы просто исключить бесконечности и nans, может быть быстрее использовать метод try-exc, а затем использовать 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

Это в значительной степени совпадает с тем, что принимает float, за исключением начального и конечного пробелов и некоторых небольших различий для nans (дополнительные 's' для сигнализации nans и диагностическая информация). Когда мне нужно числовое регулярное выражение, я обычно начинаю с этого и редактирую ненужные мне биты.

N.B. возможно , что float может быть медленнее, чем регулярное выражение, поскольку он должен не только анализировать строку, но и превращать ее в float, что является довольно сложным вычислением; все же было бы сюрпризом, если бы это было так.

2 голосов
/ 12 февраля 2010

Не совсем. Принуждение является приемлемым способом сделать это.

0 голосов
/ 12 февраля 2010

Вы можете сначала попытаться скомпилировать свое регулярное выражение, но я думаю, что оно все равно будет медленнее.

Кроме того, если вы хотите знать, является ли ваша строка числом, потому что вы собираетесь делать с ней вычисления, вам все равно придется ее принудительно привести.

...