Как проверить, является ли строка числом (с плавающей запятой)?

Как лучше всего проверить, может ли строка быть представлена ​​в виде числа в Python?

В настоящее время у меня есть следующая функция:

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

Что не только некрасиво и медленно, но и кажется неуклюжим. Однако я не нашел лучшего метода, потому что вызов float в основной функции еще хуже.


person Daniel Goldberg    schedule 09.12.2008    source источник
comment
Что не так с вашим текущим решением? Он короткий, быстрый и читаемый.   -  person Colonel Panic    schedule 22.03.2013
comment
И вам не нужно просто возвращать True или False. Вместо этого вы можете вернуть значение, измененное соответствующим образом - например, вы можете использовать это, чтобы заключить нечисловые значения в кавычки.   -  person Thruston    schedule 25.05.2013
comment
Не лучше ли вернуть результат float (s) в случае успешного преобразования? У вас все еще есть проверка на успех (результат - Ложь), и у вас действительно есть преобразование, которое вы, вероятно, в любом случае захотите.   -  person Jiminion    schedule 25.07.2013
comment
Thruston - я понимаю вашу точку зрения, но тогда проверка менее тривиальна.   -  person Jiminion    schedule 25.07.2013
comment
Несмотря на то, что этот вопрос более старый, я просто хотел сказать, что это элегантный способ, который задокументирован как EAFP. Так что, вероятно, лучшее решение для такого рода проблем.   -  person thiruvenkadam    schedule 07.10.2013
comment
Это кажется нормальным, если вы не проверяете вводимые пользователем данные, поскольку locale.atoi (0,1,00) оценивается как 100 ....   -  person Woody Pride    schedule 20.06.2014
comment
Очень полезная функция. Кроме того, если вы хотите разрешить пробел, например 1e + 2 и т. Д., Эту функцию необходимо изменить.   -  person cppcoder    schedule 29.07.2014
comment
Если вы не знаете, является ли входное значение строкой, вы также можете поймать TypeError   -  person karlgold    schedule 03.08.2014
comment
pythoncentral .io /, поможет.   -  person laike9m    schedule 27.03.2015
comment
Возвращает результат float(s) в случае успеха или None в случае неудачи. Тогда вы получите поведение True / False, а также сможете напрямую использовать результат.   -  person smci    schedule 05.04.2015
comment
связанные: Извлечь значение float / double   -  person jfs    schedule 23.08.2015
comment
Не возвращать результат float (s) или None в случае неудачи. если вы затем используете его как x = float('0.00'); if x: use_float(x);, в вашем коде есть ошибка. Истинные значения являются причиной того, что эти функции вызывают исключение, а не возвращают None. Лучшее решение - просто избежать служебной функции и заключить вызов float в try catch, когда вы хотите его использовать.   -  person ovangle    schedule 05.01.2016
comment
Это часть проблемы, рассмотренной в сообщении stackoverflow.com/questions/36903462/adding-numbers-in-a-string/   -  person Supreet Sethi    schedule 28.04.2016
comment
Предупреждение: во фрагменте говорится, что любой объект, который автоматически приводит к типу float, является числом, и это может вводить в заблуждение. Например, простой bool результат будет числом, потому что float (True) возвращает действительное значение 1.0.   -  person dbra    schedule 01.02.2017
comment
не медленный. int (s) или float (s), вероятно, почти так же быстро, как то, что интерпретатор python использует для таких вещей, и может даже иметь под собой некоторый код C. In [17]: time_it (int, '333', count = 1) Out [17]: 4.0531158447265625e-06 Чертовски быстро.   -  person Samantha Atkins    schedule 16.08.2019
comment
Вероятно, вы захотите избавиться от части ValueError, иначе это вызовет исключение, когда получит список / dict для ввода.   -  person orcaman    schedule 27.02.2020
comment
@Colonel Panic, это тоже медленно   -  person Ievgen Naida    schedule 02.06.2021


Ответы (35)


Что не только некрасиво и медленно

Я бы не согласился с обоими.

Регулярное выражение или другой метод синтаксического анализа строк будет уродливее и медленнее.

Я не уверен, что что-то намного может быть быстрее, чем указано выше. Он вызывает функцию и возвращает ее. Try / Catch не вызывает особых накладных расходов, поскольку наиболее частое исключение выявляется без тщательного поиска кадров стека.

Проблема в том, что любая функция числового преобразования дает два вида результатов.

  • Число, если число действительное
  • Код состояния (например, через errno) или исключение, чтобы показать, что действительный номер не может быть проанализирован.

C (в качестве примера) пытается обойти это несколькими способами. Python излагает это ясно и ясно.

Я думаю, что ваш код для этого идеален.

person S.Lott    schedule 09.12.2008
comment
Я не думаю, что код идеален (но я думаю, что он очень близок): чаще всего помещают только тестируемую часть в предложение try, поэтому я бы поместил return True в else статьи try. Одна из причин заключается в том, что с кодом в вопросе, если бы мне пришлось его просмотреть, мне пришлось бы проверить, что второй оператор в предложении try не может вызвать ValueError: конечно, это не требует слишком много времени или мощности мозга , но зачем использовать их, когда они не нужны? - person Eric O Lebigot; 05.07.2013
comment
Ответ кажется убедительным, но заставляет меня задаться вопросом, почему он не предоставляется прямо из коробки ... Я скопирую его и буду использовать в любом случае. - person sage; 29.12.2013
comment
Как ужасно. Как насчет того, чтобы меня не волновало, какое число такое, просто то, что это число (которое привело меня сюда)? Вместо однострочного IsNumeric() я получаю либо try / catch, либо другую упаковку try / catch. фу - person Basic; 10.03.2014
comment
@Basic Я не понимаю твоей точки зрения. Назовите вашу функцию, которая выполняет проверку IsNumeric, и используйте эту функцию. Это идея использования функций - однострочные. - person Nils Lindemann; 13.03.2014
comment
@Nils Я хочу сказать, что это настолько очевидная и простая операция, доступная во всех других языках высокого уровня, которые я использовал, что ее отсутствие кажется вопиющим упущением. С другой стороны, здесь не место для затяжных дискуссий, так что давайте согласимся не соглашаться. - person Basic; 13.03.2014
comment
@Basic - [Проверка того, является ли строка числом] доступна на всех других языках высокого уровня - я согласен с вами по большей части предложения, из которого я извлек эту цитату, но я не согласен с цитируемым текстом. Доступен ли он на Java (и если да, то с какой версии JDK?) Последний раз я проверял (по общему признанию, несколько лет назад), не было. - person ArtOfWarfare; 07.08.2014
comment
@ArtOfWarfare Ключевой момент - это то, где я сказал, что использовал ... Не имея намерения начать войну, я по возможности избегаю Java. Тот факт, что в нем отсутствует IsNumeric(), меня совсем не удивляет. - person Basic; 08.08.2014
comment
@Basic - Мне любопытно, какие языки вы использовали с этой функцией из коробки? Мы рассмотрели, что у Python и Java его нет, и если в Java его нет, мы можем исключить C, C ++ и, возможно, C # тоже. В Objective-C этого нет. Осталось не так много популярных языков высокого уровня ... есть ли он в Ruby? Есть ли это в PHP? Perl? На данный момент я думаю, что я назвал все популярные / основные языки высокого уровня ... - person ArtOfWarfare; 08.08.2014
comment
@ArtOfWarfare PHP, Javascript и VB.Net в моей голове. В T-SQL есть ISNUMERIC(), если вы отнесете это к языку. В C # есть Double.TryParse(), который вернет логическое значение, хотя он может быть немного более нечетким (может опционально разрешать пробелы, разделители тысяч и т. Д.). В любом случае, мы перехватываем эту ветку комментариев, поэтому я вернусь и удалю свои сегодняшние комментарии через несколько часов. - person Basic; 08.08.2014
comment
@Basic - Ах, я пренебрегал JS. SQL - настолько узконаправленный язык, что я бы не стал сравнивать его с Python или любыми другими языками программирования общего назначения высокого уровня. И я должен признаться, что не знаком с PHP, VB или C #. Ваши комментарии достаточно справедливы. Я не вижу смысла их удалять. - person ArtOfWarfare; 08.08.2014
comment
Он не предоставляется «из коробки», потому что if is_number(s): x = float(x) else: // fail - это то же количество строк кода, что и try: x = float(x) catch TypeError: # fail. Эта функция полезности - совершенно ненужная абстракция. - person ovangle; 05.01.2016
comment
Но все дело в библиотеках в абстракции. Наличие функции isNumber (на любом языке) очень помогает, потому что вы можете встроить ее прямо в операторы if и иметь гораздо более читаемый и поддерживаемый код, который полагается на блоки try-catch. Кроме того, если вам нужно использовать код более одного раза в более чем одном классе / модуле, вы использовали больше строк кода, чем было бы у встроенной функции. - person JamEngulfer; 18.03.2016

Если вы ищете целые числа синтаксического анализа (положительные, беззнаковые) вместо чисел с плавающей запятой, вы можете использовать _ 1_ для строковых объектов.

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

Строковые методы - isdigit(): Python2 , Python3

Также есть кое-что о строках Unicode, с которыми я не слишком хорошо знаком Unicode - десятичный / десятичный

person Zoomulator    schedule 09.12.2008
comment
Это отрицательно и на негативах - person intrepion; 23.10.2009
comment
Не работает и с экспонентами: '1e3'.isdigit () - ›False - person ssc; 12.05.2011
comment
Хотя Number! = Digit, люди, которые ищут способы проверить, содержит ли строка целое число, вполне могут натолкнуться на этот вопрос, а подход isDigit вполне может быть идеально подходящим для их приложения. - person Adam Parkin; 21.08.2012
comment
Даже если этот ответ не решает вопрос OP, чтобы решить проблему с поплавками, как насчет того, чтобы сделать что-то вроде a.isdigit () или a.replace ('.', ''). Isdigit ()? - person Robert Smith; 24.08.2012
comment
@AdamParkin: isdigit() и int() имеют разные мнения о том, что такое целое число, например, для символа Unicode u'\u00b9': u'¹'.isdigit() равно True, но int(u'¹') вызывает ValueError. - person jfs; 16.11.2012
comment
Имя isdigit вводит в заблуждение с самого начала, поскольку цифра означает [0-9] - person Iulius Curt; 17.01.2013
comment
+1: isdigit () может быть не тем, что искал OP, но это именно то, что я хотел. Возможно, этот ответ и метод не охватывают все типы чисел, но он по-прежнему очень актуален, вопреки аргументам о его точности. Хотя число! = Цифра, цифра по-прежнему является подмножеством числа, особенно чисел, которые являются положительными, неотрицательными и используют основание 1-10. Кроме того, этот метод особенно полезен и краток для случаев, когда вы хотите проверить, является ли строка числовым идентификатором или нет, который часто попадает в подмножество чисел, которое я только что описал. - person Justin Johnson; 19.06.2013
comment
@JustinJohnson: вы читали мой предыдущий комментарий? Вероятно, вы захотите вместо этого isdecimal(). - person jfs; 13.10.2014
comment
@ J.F.Sebastian Вы правы; isdecimal() - правильный метод для использования в описанном мной сценарии. - person Justin Johnson; 17.10.2014
comment
+1, я искал это решение на основе моего запроса Google, поэтому любой, кто сказал, что этот ответ неуместен, не думал ни о ком, кроме OP. Поскольку у переполнения стека так много ответов, которые появляются в Google, это абсолютно актуально для тех, кто ищет этот тип решения (например, если вам нужно удалить любые нецифровые цифры из номера телефона: phone = ''.join([n for n in someString if n.isdigit()])) - person RattleyCooper; 03.02.2015
comment
Как у этого есть 800+ голосов, когда это совершенно неправильно? Тот факт, что здесь есть комментарии типа +1, это не отвечает на вопрос, но все равно помогает мне, шокирует меня. -1. - person Barry; 06.07.2015
comment
@DuckPuncher: для телефонных номеров вам нужен _ 1_ вместо isdigit() здесь (если someString может содержать символы, отличные от ascii). - person jfs; 20.10.2015
comment
Это бомба на отрицательных числах, которые являются числами, о которых спрашивал ОП (ОП никогда не указывал положительные). - person Tommy; 11.04.2016
comment
Как говорили другие, это хороший метод, но совершенно не подходит для вопроса. В противном случае люди захотят отметить мой ответ «курица» как правильный. Это то, что я ел на ужин вчера вечером, и поэтому оно верное и правильное, просто не имеющее отношения к заданному вопросу. Если серьезно, то да, этот метод - хороший метод, но он совершенно неверен для заданного вопроса, который конкретно относится к плавает, и поэтому за него не следует голосовать. - person Del; 14.11.2016
comment
@ Jason9987 цифра - это один из 10 символов [0-9]. Так что математические определения здесь все равно не сработают. - person Gangnus; 01.08.2017
comment
Вы можете разделить на "." и проверьте, являются ли обе половины is_digit (), чтобы проверить число с плавающей запятой. - person Paul Kenjora; 06.12.2017

TL; DR Лучшее решение - s.replace('.','',1).isdigit()

Я сделал несколько контрольные показатели, сравнивающие различные подходы

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()

Если строка не является числом, блок исключений выполняется довольно медленно. Но что еще более важно, метод 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()

введите описание изображения здесь

person Community    schedule 13.05.2014
comment
за красивые графики +1. Я видел тест и видел график, все вещи TL; DR стали ясными и интуитивно понятными. - person jcchuks; 18.11.2016
comment
Я согласен с @JCChuks: график очень помогает быстро получить все TL; DR. Но я думаю, что TL; DR (например: TL; DR: лучшее решение - s.replace('.','',1).isdigit()) должен появиться в начале этого ответа. В любом случае он должен быть принятым. Спасибо! - person Simon C.; 10.03.2017
comment
TLDR вводит в заблуждение и лукавит. Быть лучшим не коррелирует ни с одним тестом производительности. Например, я обычно ценю удобочитаемость намного больше, чем микрооптимизации, поэтому тесты почти не имеют значения при определении лучшего решения для моего контекста. TL; DR будет более точным из этого заявленного: лучше всего, если ранжируется по времени выполнения из небольшого набора произвольных тестов. - person Corey Goldberg; 28.04.2018
comment
честно говоря, но в TLDR я также не сказал, что он основан на тестах. Мне также кажется, что это наиболее удобочитаемое решение. - person ; 29.04.2018
comment
Обратите внимание, что добавление .lstrip('-') для отрицательных чисел увеличивает время выполнения функции is_number_repl_isdigit в 1,5 раза. - person Alexander McFarlane; 22.08.2018
comment
Можете ли вы включить fastnumbers в график (см. stackoverflow.com/a/25299619/1399279, чтобы узнать, как использовать его в этом приложении)? - person SethMMorton; 22.08.2018
comment
Этот метод не обрабатывает отрицательные числа (тире). Я бы посоветовал просто использовать метод с плавающей запятой, поскольку он менее подвержен ошибкам и будет работать каждый раз. - person Urchin; 10.04.2019
comment
Важно отметить, что даже в предположении, что тире быть не может, метод replace-isdigit работает быстрее только для нечисловых (ложный результат), а метод try-except быстрее для чисел (истинный результат). Если большая часть вашего ввода является допустимым, вам лучше использовать решение try-except! - person Markus von Broady; 24.04.2019
comment
Не работает с экспоненциальной записью, такой как '1.5e-9', или с отрицаниями. - person EL_DON; 17.10.2019
comment
Отлично, сделал что-то сопоставимое, без хороших диаграмм, но потом тысячи итераций. Когда я запускал намного больше случаев, try / catch становился немного дороже в отрицательных случаях, чем регулярное выражение, но при использовании непосредственно в if (if test_trycatch_function (x): ... else: ...) потребовалось двойное время регулярного выражения. Мои познания в Python не так уж глубоки, поэтому я не понимаю, зачем просто запускать или присваивать его переменной, которая больше не используется, я не знаю. Может, какой-то оптимизатор его полностью пропускает? - person benzhi; 17.03.2020
comment
Великолепно, если не считать очевидных предупреждений о ложных отрицаниях для возведения в степень и отрицательных значений, которые вы можете тривиально исправить, просто связав s.replace() вызовов в цепочку. Например, s.replace('.','',1).replace('e-','',1).replace('e','',1).isdigit() обрабатывает возведение в степень. Чтобы затем обработать негативы, просто удалите первый символ слева, если это тире. Например, s.lstrip('-').replace('.','',1).replace('e-','',1).replace('e','',1).isdigit(). Да, я тщательно протестировал этот однострочный запрос и могу подтвердить, что он ведет себя так, как ожидалось. - person Cecil Curry; 25.09.2020
comment
Вы должны терпимо относиться к пустому пространству и принимать знак, поэтому comp = re_compile("^\s*[+-]?\d+?\.\d+?\s*$"). - person Hans Ginzel; 30.10.2020

Есть одно исключение, которое вы можете принять во внимание: строка NaN.

Если вы хотите, чтобы is_number возвращал FALSE для 'NaN', этот код не будет работать, поскольку Python преобразует его в свое представление числа, которое не является числом (поговорим о проблемах с идентификацией):

>>> float('NaN')
nan

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

G.

person W7GVR    schedule 01.09.2010
comment
Фактически, NaN может быть хорошим значением для возврата (а не False), если переданный текст на самом деле не является представлением числа. Проверка на это - своего рода боль (для типа Python float действительно нужен метод), но вы можете использовать его в вычислениях, не вызывая ошибок, и вам нужно только проверить результат. - person kindall; 10.06.2011
comment
Другое исключение - строка 'inf'. Либо inf, либо NaN также могут иметь префикс + или - и по-прежнему приниматься. - person agf; 23.05.2012
comment
Если вы хотите вернуть False для NaN и Inf, измените строку на x = float (s); return (x == x) и (x - 1! = x). Это должно вернуть True для всех чисел с плавающей запятой, кроме Inf и NaN. - person RyanN; 16.03.2013
comment
x-1 == x верно для больших чисел с плавающей запятой меньше inf. Начиная с Python 3.2, вы можете использовать math.isfinite для проверки чисел, которые не являются ни NaN, ни бесконечными, или проверить оба math.isnan и math.isinf до этого. - person Steve Jessop; 22.01.2014

как насчет этого:

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

который вернет истину, только если он есть или нет '.' в строке цифр.

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

вернет false

edit: только что увидел еще один комментарий ... можно добавить .replace(badstuff,'',maxnum_badstuff) для других случаев. если вы передаете соль, а не произвольные приправы (ref: xkcd # 974), это подойдет: P

person haxwithaxe    schedule 25.05.2012
comment
Однако это не учитывает отрицательные числа. - person Michael Barton; 24.10.2014
comment
Или числа с показателями, например 1.234e56 (которые также могут быть записаны как +1.234E+56 и еще несколько вариантов). - person Alfe; 22.04.2016
comment
re.match(r'^[+-]*(0[xbo])?[0-9A-Fa-f]*\.?[0-9A-Fa-f]*(E[+-]*[0-9A-Fa-f]+)$', 'str') должен лучше определять число (но не все, я этого не утверждаю). Я не рекомендую использовать это, гораздо лучше использовать исходный код Вопросника. - person Baldrickk; 09.02.2017
comment
если вам не нравится это решение, прочтите это перед тем, как голосовать против! - person aloisdg; 23.02.2018
comment
чувак, это самое умное решение, которое я когда-либо видел на этом сайте !, молодец! - person Karam Qusai; 06.12.2019

Обновлено после того, как Альфе указал, что вам не нужно отдельно проверять float, поскольку комплекс обрабатывает оба:

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
person Community    schedule 26.07.2010
comment
Я не согласен. Это ОЧЕНЬ маловероятно при нормальном использовании, и вам лучше создать вызов is_complex_number (), когда вы их используете, чем обременять вызов дополнительной операцией для 0,0001% вероятности неправильной работы. - person Jiminion; 25.07.2013
comment
Вы можете полностью удалить float() материал и просто проверить успешность вызова complex(). Все, что проанализировано float(), может быть проанализировано complex(). - person Alfe; 22.04.2016
comment
Эта функция вернет значения NaN и Inf Pandas в виде числовых значений. - person fixxxer; 29.05.2016
comment
complex('(01989)') вернет (1989+0j). Но float('(01989)') потерпит неудачу. Поэтому я считаю, что использовать complex - не лучшая идея. - person plhn; 20.12.2018
comment
Ура. Странно, что complex() принимает синтаксис с разделителями ( и ) - предположительно для учета сложения составных векторов в мнимой плоскости, лежащей в основе комплексных чисел, но все же. Как предлагает @plhn, использование complex() здесь приводит к ложным срабатываниям. Не делайте этого в производственном коде. Честно говоря, s.lstrip('-').replace('.','',1).replace('e-','',1).replace('e','',1).isdigit() остается оптимальным решением для большинства случаев использования. - person Cecil Curry; 25.09.2020

Что не только некрасиво и медленно, но и кажется неуклюжим.

Может потребоваться некоторое привыкание, но это питонический способ сделать это. Как уже указывалось, альтернативы хуже. Но есть еще одно преимущество такого подхода: полиморфизм.

Центральная идея утиного набора текста заключается в том, что «если он ходит и говорит как утка, значит, это утка». Что, если вы решите, что вам нужно создать подкласс строки, чтобы вы могли изменить способ определения, можно ли что-то преобразовать в число с плавающей запятой? Или что, если вы решите полностью протестировать какой-то другой объект? Вы можете делать это, не меняя приведенный выше код.

Другие языки решают эти проблемы с помощью интерфейсов. Я сохраню анализ того, какое решение лучше для другой темы. Дело, однако, в том, что python явно находится на стороне утиного ввода в уравнении, и вам, вероятно, придется привыкнуть к подобному синтаксису, если вы планируете много программировать на Python (но это не значит, что конечно должно нравиться).

Еще одна вещь, которую вы, возможно, захотите принять во внимание: Python довольно быстро генерирует и перехватывает исключения по сравнению с множеством других языков (например, в 30 раз быстрее, чем .Net). Черт возьми, сам язык даже выдает исключения, чтобы сообщить неисключительные, нормальные условия программы (каждый раз, когда вы используете цикл for). Таким образом, я бы не стал слишком беспокоиться об аспектах производительности этого кода, пока вы не заметите серьезную проблему.

person Jason Baker    schedule 11.12.2008
comment
Еще одно обычное место, где Python использует исключения для базовых функций, - это hasattr(), который представляет собой просто getattr() вызов, заключенный в try/except. Тем не менее, обработка исключений происходит медленнее, чем обычное управление потоком, поэтому его использование для чего-то, что будет истинным большую часть времени, может привести к снижению производительности. - person kindall; 10.06.2011
comment
Кажется, что если вы хотите однострочник, вы SOL - person Basic; 10.03.2014
comment
Также питонизмом является идея, что лучше попросить прощения, чем разрешения, в отношении влияния дешевых исключений. - person heltonbiker; 26.04.2016

Для 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
person Sdwdaw    schedule 08.09.2015
comment
Не работает с такими вещами, как 1.234e56 и т.п. Кроме того, мне было бы интересно, как вы узнали, что 99999999999999999999e99999999999999999999 не является числом. Попытка разобрать это быстро выясняет. - person Alfe; 22.04.2016
comment
Это работает примерно на 30% быстрее, чем принятое решение для списка из 50 метров строк и на 150% быстрее для списка из 5 тысяч строк. ???? - person Zev Averbach; 21.02.2017

Этот ответ содержит пошаговое руководство с функцией с примерами поиска строки:

  • Положительное целое число
  • Положительное / отрицательное - целое / с плавающей запятой
  • Как отбросить строки NaN (не числа) при проверке числа?

Проверьте, является ли строка положительным целым числом

Вы можете использовать str.isdigit() для проверки является ли данная строка положительным целым числом.

Примеры результатов:

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

Проверить строку как положительное / отрицательное - целое число / число с плавающей запятой

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

Отбросить строки NaN (не числа) при проверке числа

Вышеупомянутые функции вернут True для строки NAN (не числа), потому что для Python это допустимое число с плавающей запятой, представляющее, что это не число. Например:

>>> is_number('NaN')
True

Чтобы проверить, является ли число NaN, вы можете использовать math.isnan() как:

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

>>> math.isnan(nan_num)
True

Или, если вы не хотите импортировать дополнительную библиотеку, чтобы проверить это, вы можете просто проверить ее, сравнив ее с самим собой, используя ==. Python возвращает False, когда nan float сравнивается с самим собой. Например:

# `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, которая соответствует вашим требованиям.

person Anonymous    schedule 11.02.2018

Для строк, не являющихся числами, 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 выигрывает в обоих случаях
person SethMMorton    schedule 14.08.2014
comment
Я поправляюсь: -} просто не похоже, что он это делал. Возможно, использование таких имен, как prep_code_basis и prep_code_re_method, предотвратило бы мою ошибку. - person Alfe; 22.04.2016
comment
Не могли бы вы объяснить, как работает ваш модуль, хотя бы для функции isfloat? - person Solomon Ucko; 05.05.2016
comment
@SolomonUcko Вот ссылка на исходный код для части проверки строк: github.com/SethMMorton/fastnumbers/blob/v1.0.0/src/. По сути, он проходит по каждому символу в строке по порядку и проверяет, что он следует шаблону для действительного числа с плавающей запятой. Если ввод уже является числом, он просто использует быстрый PyFloat_Check . - person SethMMorton; 05.05.2016
comment
Протестировано с лучшими альтернативами в этом потоке, я подтверждаю, что это решение является безусловно самым быстрым. Второй самый быстрый метод - str(s).strip('-').replace('.','',1).isdigit(), что примерно в 10 раз медленнее! - person Alexander McFarlane; 22.08.2018
comment
Обратите внимание, что timeit.timeit выполняет оператор 1 миллион раз. Я был сбит с толку, почему эти цифры казались такими медленными. - person mic; 13.10.2020
comment
Это отличное решение, и, честно говоря, оно должно быть ближе к вершине. Для этого действительно требуется новая библиотека, но она проста в использовании и работает интуитивно понятно. Было именно то, что я искал. Спасибо @SethMMorton - person rfadams; 05.02.2021

Просто имитируйте C #

В C # есть две разные функции, обрабатывающие синтаксический анализ скалярных значений:

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

float.parse ():

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

Примечание. Если вам интересно, почему я изменил исключение на TypeError, вот документация. < / em>

float.try_parse ():

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

Примечание: вы не хотите возвращать логическое значение «False», потому что это все еще тип значения. Нет лучше, потому что это указывает на неудачу. Конечно, если вам нужно что-то другое, вы можете изменить параметр ошибки на все, что захотите.

Чтобы расширить 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

И великий мудрец Пифонас сказал Святому Престолу Шарпису: «Все, что ты можешь сделать, я могу сделать лучше; я могу сделать все лучше, чем ты».

person Evan Plaice    schedule 18.02.2012
comment
В последнее время я кодировал в основном JS и на самом деле не тестировал это, поэтому могут быть некоторые незначительные ошибки. Если увидите, не стесняйтесь исправлять мои ошибки. - person Evan Plaice; 18.02.2012
comment
Чтобы добавить поддержку комплексных чисел, см. Ответ @Matthew Wilcoxson. stackoverflow.com/a/3335060/290340. - person Evan Plaice; 18.02.2012
comment
Использование ! вместо not может быть незначительной ошибкой, но вы определенно не можете назначать атрибуты встроенному float в CPython. - person BlackJack; 28.08.2016
comment
проголосовали против за перехват всех исключений без разбора и за использование несуществующего ключевого слова throw - person Janus Troelsen; 07.09.2020

Я знаю, что это особенно старый, но я бы добавил ответ, который, как мне кажется, охватывает информацию, отсутствующую в ответе с наибольшим количеством голосов, который может быть очень ценным для любого, кто найдет это:

Для каждого из следующих методов соедините их счетчиком, если вам нужно принять какой-либо ввод. (Предполагая, что мы используем голосовые определения целых чисел, а не 0-255 и т. Д.)

x.isdigit() хорошо подходит для проверки, является ли x целым числом.

x.replace('-','').isdigit() хорошо подходит для проверки, является ли x отрицательным (проверка - в первой позиции)

x.replace('.','').isdigit() хорошо подходит для проверки, является ли x десятичным числом.

x.replace(':','').isdigit() хорошо подходит для проверки, является ли x соотношением.

x.replace('/','',1).isdigit() хорошо подходит для проверки, является ли x дробью.

person Aruthawolf    schedule 05.01.2016
comment
Хотя для дробей вам, вероятно, нужно сделать x.replace('/','',1).isdigit(), иначе даты, такие как 4/7/2017, будут неверно интерпретированы как числа. - person Yuxuan Chen; 07.04.2017
comment
Лучшие способы связать условия: stackoverflow.com/q/3411771/5922329 - person Daniel Braun; 11.04.2018

Преобразование в float и перехват ValueError, вероятно, самый быстрый способ, поскольку float () специально предназначен для этого. Все остальное, что требует синтаксического анализа строк (регулярное выражение и т. Д.), Скорее всего, будет медленнее из-за того, что оно не настроено для этой операции. Мои 0,02 доллара.

person codelogic    schedule 09.12.2008
comment
Ваши 2e-2 доллара тоже являются плавающими (дополнительный аргумент в пользу использования float :) - person tzot; 10.12.2008
comment
@tzot НИКОГДА не используйте число с плавающей запятой для представления денежной стоимости. - person Luke; 07.11.2012
comment
@Luke: Я полностью согласен с вами, хотя я никогда не предлагал использовать числа с плавающей запятой для представления денежных значений; Я только что сказал, что денежные значения могут быть представлены как числа с плавающей запятой :) - person tzot; 08.11.2012

Вы можете использовать строки 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

person Blackzafiro    schedule 04.03.2013
comment
для неотрицательных int это нормально ;-) - person andilabs; 22.03.2014
comment
s.isdecimal() проверяет, является ли s строка неотрицательным целым числом. s.isnumeric() включает символы, которые int() отклоняют. - person jfs; 19.10.2014

Итак, чтобы собрать все вместе, проверяя 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
person a1an    schedule 23.03.2012
comment
Пока лучший ответ. Спасибо - person anish; 15.01.2020

Я хотел посмотреть, какой метод самый быстрый. В целом наилучшие и наиболее последовательные результаты дает функция check_replace. Самые быстрые результаты дает функция check_exception, но только в том случае, если не было запущено исключение - это означает, что ее код является наиболее эффективным, но накладные расходы на создание исключения довольно велики.

Обратите внимание, что проверка успешного приведения - единственный точный метод, например, он работает с check_exception, но две другие тестовые функции вернут 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))

Вот результаты с Python 2.7.10 на MacBook Pro 13 2017 года:

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

Вот результаты с Python 3.6.5 на MacBook Pro 13 2017 года:

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

Вот результаты PyPy 2.7.13 на MacBook Pro 13 2017 года:

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
person Ron Reiter    schedule 16.01.2013
comment
Вы также должны проверить производительность на недопустимые случаи. С этими числами не возникает никаких исключений, и это как раз самая медленная часть. - person Ugo Méda; 28.01.2013
comment
@ UgoMéda я последовал твоему совету из 2013 года и сделал это :) - person Ron Reiter; 28.04.2018
comment
Обратите внимание, что проверка успешного приведения - единственный точный метод ‹- на самом деле это не так. Я провел ваш тест, используя регулярное выражение в моем ответе выше, и он действительно работает быстрее, чем регулярное выражение. Я добавлю результаты к своему ответу выше. - person David Ljung Madison Stellar; 29.01.2020
comment
Кстати, забавно, что ваш создатель плохих чисел действительно может создавать некоторые допустимые числа, хотя это бывает довольно редко. :) - person David Ljung Madison Stellar; 29.01.2020

Вход может быть следующим:

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

Проверяет, является ли данная переменная плавающей. Строки с плавающей запятой состоят из необязательного знака, любого количества цифр, ...

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- Если вы уверены, что содержимое переменной - Строка:

используйте метод 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
person Community    schedule 06.10.2018
comment
что такое ast? - person ; 06.10.2018
comment
понимание типов - person ; 08.01.2021
comment
Это не удается при проверке is_numeric("String 1") Обернул метод в try / except и работает. - person Ramon; 10.01.2021

str.isnumeric()

Вернуть True, если все символы в строке числовые и есть хотя бы один символ, в противном случае False. Числовые символы включают символы цифр и все символы, которые имеют свойство числового значения Unicode, например U + 2155, ВУЛГАРНАЯ ФРАКЦИЯ ОДИН ПЯТЫЙ. Формально числовые символы - это символы со значением свойства Numeric_Type = Digit, Numeric_Type = Decimal или Numeric_Type = Numeric.

str.isdecimal()

Вернуть True, если все символы в строке являются десятичными и есть хотя бы один символ, в противном случае False. Десятичные символы - это те, которые можно использовать для формирования чисел с основанием 10, например U + 0660, АРАБСКО-ИНДИКАЦИОННАЯ ЦИФРА НУЛЬ. Формально десятичный символ - это символ из общей категории Unicode «Nd».

Оба доступны для строковых типов из Python 3.0.

person zardosht    schedule 15.04.2020

Я сделал тест на скорость. Предположим, что если строка вероятно является числом, стратегия try / except является наиболее быстрой из возможных. Если строка вряд ли будет быть числом и вас интересует проверка Целочисленного, стоит провести некоторый тест (это цифра плюс заголовок '-'). Если вы хотите проверить число с плавающей запятой, вы должны использовать код try / except без выхода.

person FxIII    schedule 12.10.2010

Мне нужно было определить, преобразуется ли строка в базовые типы (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) 
person astrodsg    schedule 03.07.2014

Я думаю, что ваше решение в порядке, но существует правильная реализация регулярного выражения.

Кажется, есть много ненависти к регулярным выражениям к этим ответам, которые я считаю необоснованными, регулярные выражения могут быть достаточно чистыми, правильными и быстрыми. Это действительно зависит от того, что вы пытаетесь сделать. Первоначальный вопрос заключался в том, как вы можете «проверить, может ли строка быть представлена ​​как число (с плавающей запятой)» (согласно вашему заголовку). Предположительно, вы захотите использовать числовое значение / значение с плавающей запятой после того, как проверите, что оно действительно, и в этом случае ваш try / except имеет большой смысл. Но если по какой-то причине вы просто хотите подтвердить, что строка является числом, тогда регулярное выражение также работает нормально, но его трудно понять правильно. Я думаю, что большинство ответов на регулярные выражения до сих пор, например, не анализируют должным образом строки без целой части (например, «.7»), которая является плавающей для Python. И это немного сложно проверить в одном регулярном выражении, где дробная часть не требуется. Я включил два регулярных выражения, чтобы показать это.

Это поднимает интересный вопрос о том, что такое «число». Вы включаете "inf", который действителен как float в python? Или вы включаете числа, которые являются «числами», но, возможно, не могут быть представлены в python (например, числа, которые больше, чем максимальное значение с плавающей запятой).

Есть также двусмысленность в том, как вы разбираете числа. Например, как насчет «-20»? Это «число»? Это законный способ представлять «20»? Python позволит вам сделать «var = --20» и установить его на 20 (хотя на самом деле это потому, что он обрабатывает его как выражение), но float («- 20») не работает.

В любом случае, без дополнительной информации, вот регулярное выражение, которое, как я считаю, охватывает все целые и плавающие по мере того, как 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

Выполнение кода тестирования в ответе @ ron-reiter показывает, что это регулярное выражение на самом деле быстрее, чем обычное регулярное выражение, и намного быстрее обработка неверных значений, чем исключение, что имеет некоторый смысл. Полученные результаты:

check_regexp with good floats: 18.001921
check_regexp with bad floats: 17.861423
check_regexp with strings: 17.558862
check_correct_regexp with good floats: 11.04428
check_correct_regexp with bad floats: 8.71211
check_correct_regexp with strings: 8.144161
check_replace with good floats: 6.020597
check_replace with bad floats: 5.343049
check_replace with strings: 5.091642
check_exception with good floats: 5.201605
check_exception with bad floats: 23.921864
check_exception with strings: 23.755481
person David Ljung Madison Stellar    schedule 10.05.2019
comment
Надеюсь, что это правда - хотелось бы услышать о любых контрпримерах. :) - person David Ljung Madison Stellar; 11.05.2019

RyanN предлагает

Если вы хотите вернуть False для NaN и Inf, измените строку на x = float (s); return (x == x) и (x - 1! = x). Это должно вернуть True для всех чисел с плавающей запятой, кроме Inf и NaN.

Но это не совсем работает, потому что для достаточно больших чисел с плавающей запятой x-1 == x возвращает true. Например, 2.0**54 - 1 == 2.0**54

person philh    schedule 29.07.2013

Этот код обрабатывает экспоненты, числа с плавающей запятой и целые числа без использования регулярного выражения.

return True if str1.lstrip('-').replace('.','',1).isdigit() or float(str1) else False
person ravi tanwar    schedule 16.12.2018

В наиболее общем случае для числа с плавающей запятой нужно позаботиться о целых и десятичных числах. Возьмем для примера строку "1.1".

Я бы попробовал одно из следующего:

1. ›isnumeric ()

word = "1.1"

"".join(word.split(".")).isnumeric()
>>> True

2. ›isdigit ()

word = "1.1"

"".join(word.split(".")).isdigit()
>>> True

3. ›isdecimal ()

word = "1.1"

"".join(word.split(".")).isdecimal()
>>> True

Скорость:

► Все вышеупомянутые методы имеют одинаковую скорость.

%timeit "".join(word.split(".")).isnumeric()
>>> 257 ns ± 12 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit "".join(word.split(".")).isdigit()
>>> 252 ns ± 11 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit "".join(word.split(".")).isdecimal()
>>> 244 ns ± 7.17 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
person Siddharth Satpathy    schedule 06.12.2020

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

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

Замените myvar.apppend любой операцией, которую вы хотите выполнить со строкой, если она оказывается числом. Идея состоит в том, чтобы попытаться использовать операцию float () и использовать возвращенную ошибку, чтобы определить, является ли строка числом.

person Community    schedule 16.07.2009
comment
Вы должны переместить добавляемую часть этой функции в оператор else, чтобы избежать случайного запуска исключения, если с массивом что-то не так. - person DarwinSurvivor; 24.07.2013

Я работал над проблемой, которая привела меня к этой теме, а именно, как преобразовать набор данных в строки и числа наиболее интуитивно понятным способом. После прочтения исходного кода я понял, что то, что мне нужно, отличалось двумя способами:

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
person user1508746    schedule 09.11.2014

Я также использовал упомянутую вами функцию, но вскоре заметил, что такие строки, как «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
person mathfac    schedule 15.10.2016

Вспомогательная функция пользователя:

def if_ok(fn, string):
  try:
    return fn(string)
  except Exception as e:
    return None

тогда

if_ok(int, my_str) or if_ok(float, my_str) or if_ok(complex, my_str)
is_number = lambda s: any([if_ok(fn, s) for fn in (int, float, complex)])
person Samantha Atkins    schedule 15.08.2019

Вы можете обобщить технику исключения полезным способом, вернув больше полезных значений, чем 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:]), ')'
person Thruston    schedule 24.05.2013

Попробуй это.

 def is_number(var):
    try:
       if var == int(var):
            return True
    except Exception:
        return False
person TheRedstoneLemon    schedule 30.05.2015
comment
Не отвечает is_number('10') - person geotheory; 18.08.2015
comment
@geotheory, что значит не отвечает? - person Solomon Ucko; 05.05.2016

Извините за сообщение в ветке Zombie - просто хотел завершить код для полноты ...

# is_number() function - Uses re = regex library
# Should handle all normal and complex numbers
# Does not accept trailing spaces. 
# Note: accepts both engineering "j" and math "i" but only the imaginary part "+bi" of a complex number a+bi
# Also accepts inf or NaN
# Thanks to the earlier responders for most the regex fu

import re

ISNUM_REGEXP = re.compile(r'^[-+]?([0-9]+|[0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?[ij]?$')

def is_number(str):
#change order if you have a lot of NaN or inf to parse
    if ISNUM_REGEXP.match(str) or str == "NaN" or str == "inf": 
        return True 
    else:
        return False
# A couple test numbers
# +42.42e-42j
# -42.42E+42i

print('Is it a number?', is_number(input('Gimme any number: ')))

Дайте мне любой номер: + 42.42e-42j

Это число? Правда

person DJ Swarm    schedule 22.02.2021

Для моего очень простого и очень распространенного варианта использования: is this human written string with keyboard a number?

Я прочитал большинство ответов и получил:

def isNumeric(string):
    result = True
    try:
        x = float(string)
       result = (x == x) and (x - 1 != x)
    except ValueError:
        result = False
    return result

Он вернет False для (+-)NaN и (+-)inf.

Вы можете проверить это здесь: https://trinket.io/python/ce32c0e54e

person Micka    schedule 16.07.2021

У меня похожая проблема. Вместо определения функции isNumber я хочу преобразовать список строк в числа с плавающей запятой, что в терминах высокого уровня будет выглядеть так:

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

Очевидно, что мы не можем отделить float (s) от функций isFloat (s): эти два результата должны возвращаться одной и той же функцией. Кроме того, если float (s) терпит неудачу, весь процесс терпит неудачу, вместо того, чтобы просто игнорировать неисправный элемент. Кроме того, «0» - это действительное число, которое должно быть включено в список. При отфильтровывании плохих элементов убедитесь, что не исключили 0.

Следовательно, приведенное выше понимание необходимо как-то изменить, чтобы:

  • если какой-либо элемент в списке не может быть преобразован, игнорируйте его и не генерируйте исключение
  • избегайте вызова float (ов) более одного раза для каждого элемента (один для преобразования, другой для теста)
  • если преобразованное значение равно 0, оно все равно должно присутствовать в окончательном списке

Я предлагаю решение, вдохновленное числовыми типами C #, допускающими значение NULL. Эти типы внутренне представлены структурой, которая имеет числовое значение и добавляет логическое значение, указывающее, действительно ли значение:

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]
person Alex Pinto    schedule 18.03.2018

используйте следующее: он обрабатывает все случаи: -

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')
person donald    schedule 24.02.2017

person    schedule
comment
Вы не считаете, что 1e6 представляет собой число? - person Mark Dickinson; 02.08.2018