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

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

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

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

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

Что не так с вашим текущим решением? Он короткий, быстрый и читаемый.

Colonel Panic 22.03.2013 02:52

И вам не нужно просто возвращать True или False. Вместо этого вы можете вернуть значение, измененное соответствующим образом - например, вы можете использовать это, чтобы заключить нечисловые значения в кавычки.

Thruston 25.05.2013 01:33

Не лучше ли вернуть результат float (s) в случае успешного преобразования? У вас все еще есть проверка на успех (результат - Ложь), и у вас действительно есть преобразование, которое вы, вероятно, в любом случае захотите.

Jiminion 25.07.2013 18:40

Thruston - я понимаю вашу точку зрения, но тогда проверка менее тривиальна.

Jiminion 25.07.2013 18:40

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

thiruvenkadam 07.10.2013 19:42

Это кажется нормальным, если вы не проверяете вводимые пользователем данные, поскольку locale.atoi ("0,1,00") оценивается как 100 ....

Woody Pride 20.06.2014 12:58

Очень полезная функция. Кроме того, если вы хотите разрешить пробел, например 1e + 2 и т. д., Эту функцию необходимо изменить.

cppcoder 29.07.2014 23:39

Если вы не знаете, является ли входное значение строкой, вы также можете поймать TypeError

karlgold 03.08.2014 07:44
pythoncentral.io/…, помогло бы.
laike9m 27.03.2015 07:11

Возвращает результат float(s) в случае успеха или None в случае неудачи. Тогда вы получите поведение True / False, а также сможете напрямую использовать результат.

smci 05.04.2015 11:47
Не надо возвращает результат с плавающей точкой или None в случае ошибки. если вы затем используете его как x = float('0.00'); if x: use_float(x);, у вас теперь есть ошибка в вашем коде. Истинные значения являются причиной того, что эти функции вызывают исключение, а не возвращают None. Лучшее решение - просто избегать служебной функции и окружать вызов float в try catch, когда вы хотите его использовать.
ovangle 05.01.2016 10:31

Это часть проблемы, рассмотренной в сообщении stackoverflow.com/questions/36903462/adding-numbers-in-a-string /…

Supreet Sethi 28.04.2016 05:43

Предупреждение: во фрагменте говорится, что объект Любые, автоматически переводящий бросает в положение с плавающей точкой, является числом, и это может вводить в заблуждение. Например, простой результат bool будет числом, потому что float (True) возвращает действительное значение 1.0.

dbra 01.02.2017 16:56

не медленный. int (s) или float (s), вероятно, почти так же быстро, как то, что интерпретатор python использует для таких вещей, и может даже иметь под собой некоторый код C. In [17]: time_it (int, '333', count = 1) Out [17]: 4.0531158447265625e-06 Чертовски быстро.

Samantha Atkins 16.08.2019 02:09

Вы, вероятно, захотите избавиться от части ValueError, иначе это вызовет исключение, когда получит список / dict для ввода

orcaman 27.02.2020 17:55
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1 730
16
1 485 808
35
Перейти к ответу Данный вопрос помечен как решенный

Ответы 35

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

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

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

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

Это отрицательно и на негативах

intrepion 23.10.2009 11:05

Не работает и с экспонентами: '1e3'.isdigit () -> False

ssc 12.05.2011 17:43

Хотя Number! = Digit, люди, которые ищут способы проверить, содержит ли строка целое число, вполне могут натолкнуться на этот вопрос, и подход isDigit вполне может быть идеально подходящим для их приложения.

Adam Parkin 21.08.2012 22:15

Даже если этот ответ не решает вопрос OP, чтобы решить проблему с поплавками, как насчет того, чтобы сделать что-то вроде a.isdigit () или a.replace ('.', ''). Isdigit ()?

Robert Smith 24.08.2012 23:31

@AdamParkin: isdigit() и int() имеют разные мнения о том, что такое целое число, например, для символа Unicode u'\u00b9': u'¹'.isdigit() - это True, но int(u'¹') вызывает ValueError.

jfs 16.11.2012 20:03

Название isdigit вводит в заблуждение с самого начала, так как цифра означает [0-9].

Iulius Curt 17.01.2013 15:31

+1: isdigit () может быть не тем, что искал OP, но это именно то, что я хотел. Возможно, этот ответ и метод не охватывают все типы чисел, но он по-прежнему очень актуален, вопреки аргументам о его точности. Хотя «Число! = Цифра», цифра по-прежнему является подмножеством числа, особенно чисел, которые являются положительными, неотрицательными и используют основание 1–10. Кроме того, этот метод особенно полезен и краток для случаев, когда вы хотите проверить, является ли строка числовым идентификатором или нет, который часто попадает в подмножество чисел, которое я только что описал.

Justin Johnson 19.06.2013 02:39

@JustinJohnson: ты читал мой предыдущий комментарий? Вы, вероятно, захотите isdecimal() вместо.

jfs 13.10.2014 23:50

@ J.F.Sebastian Вы правы; isdecimal() - правильный метод для использования в описанном мной сценарии.

Justin Johnson 17.10.2014 09:21

+1, я искал это решение на основе моего запроса Google, поэтому любой, кто сказал, что этот ответ неуместен, не думал ни о ком, кроме OP. Поскольку у переполнения стека так много ответов, которые появляются в Google, это абсолютно актуально для тех, кто ищет этот тип решения (например, если вам нужно удалить любые нецифровые цифры из номера телефона: phone = ''.join([n for n in someString if n.isdigit()]))

DuckPuncher 03.02.2015 18:18

Как у этого есть 800+ голосов, когда это совершенно неправильно? Тот факт, что здесь есть комментарии вроде «+1, это не ответ на вопрос, но все равно помогает мне», поражает меня. -1.

Barry 06.07.2015 22:31

@DuckPuncher: для телефонных номеров вам нужен isdecimal() вместо isdigit() (если someString может содержать символы, отличные от ascii).

jfs 20.10.2015 13:35

Это бомба на отрицательных числах, которые являются числами, о которых спрашивал ОП (ОП никогда не указывал положительные).

Tommy 11.04.2016 05:24

Как говорили другие, это хороший метод, но совершенно не подходит для вопроса. В противном случае люди захотят отметить мой ответ «курица» как правильный. Это то, что я ел на ужин вчера вечером, и поэтому он верен и верен, просто не имеет отношения к заданному вопросу. Если серьезно, да, этот метод - хороший метод, но он совершенно неверен для заданного вопроса, который конкретно ссылается на плавает, и поэтому за него не следует голосовать.

Del 14.11.2016 17:24

@ Jason9987 цифра - это один из 10 символов [0-9]. Так что математические определения здесь все равно не сработают.

Gangnus 01.08.2017 12:19

Вы можете разделить на '.' и проверьте, являются ли обе половины is_digit (), чтобы проверить число с плавающей запятой.

Paul Kenjora 06.12.2017 19:05
Ответ принят как подходящий

Which, not only is ugly and slow

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

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

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

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

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

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

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

Я не думаю, что код идеален (но я думаю, что он очень близок): чаще всего помещают Только «тестируемую» часть в предложение try, поэтому я бы поместил return True в пункт elsetry . Одна из причин заключается в том, что с кодом в вопросе, если бы мне пришлось его просмотреть, мне пришлось бы проверить, что второй оператор в предложении try не может вызвать ValueError: конечно, это не требует слишком много времени или мощности мозга , но зачем использовать их, когда они не нужны?

Eric O Lebigot 05.07.2013 12:21

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

sage 29.12.2013 03:40

Как ужасно. Как насчет того, что мне все равно, что такое число является, только то, что это число (которое привело меня сюда)? Вместо однострочного IsNumeric() я получаю либо try / catch, либо другую упаковку try / catch. фу

Basic 10.03.2014 15:22

@Basic Я не понимаю твоей точки зрения. Назовите вашу функцию, которая выполняет проверку IsNumeric, и используйте эту функцию. Это идея использования функций - однострочные.

Nils Lindemann 13.03.2014 00:38

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

Basic 13.03.2014 01:09

@Basic - «[Проверка того, является ли строка числом] доступна на всех других языках высокого уровня» - я согласен с вами по большей части предложения, из которого я извлек эту цитату, но я не согласен с цитируемым текстом. Доступен ли он на Java (и если да, то с какой версии JDK?) Последний раз я проверял (по общему признанию, несколько лет назад), не было.

ArtOfWarfare 07.08.2014 22:09

@ArtOfWarfare Ключевой момент - это то, где я сказал: «То, что я использовал» ... Не имея намерения начать войну, я по возможности избегаю Java. Отсутствие IsNumeric() меня совсем не удивляет.

Basic 08.08.2014 00:17

@Basic - Мне любопытно, какие языки вы использовали с этой функцией из коробки? Мы рассмотрели, что у Python и Java его нет, и если в Java его нет, мы можем исключить C, C++ и, возможно, C# тоже. В Objective-C этого нет. Осталось не так много популярных языков высокого уровня ... есть ли он в Ruby? Есть ли это в PHP? Perl? На данный момент я думаю, что я назвал все популярные / основные языки высокого уровня ...

ArtOfWarfare 08.08.2014 00:36

@ArtOfWarfare PHP, Javascript и VB.Net в моей голове. В T-SQL есть ISNUMERIC(), если вы отнесете это к языку. В C# есть Double.TryParse(), который возвращает логическое значение, хотя он может быть немного более нечетким (может опционально разрешать пробелы, разделители тысяч и т. д.). В любом случае, мы перехватываем эту ветку комментариев, поэтому я вернусь и удалю свои сегодняшние комментарии через несколько часов.

Basic 08.08.2014 00:45

@Basic - Ах, я пренебрегал JS. SQL - настолько узконаправленный язык, что я бы не стал сравнивать его с Python или любыми другими языками программирования общего назначения высокого уровня. И я должен признаться, что не знаком с PHP, VB или C#. Ваши комментарии достаточно справедливы. Я не вижу смысла их удалять.

ArtOfWarfare 08.08.2014 04:35

Он не предоставляется «из коробки», потому что if is_number(s): x = float(x) else: // fail имеет то же количество строк кода, что и try: x = float(x) catch TypeError: # fail. Эта функция полезности - совершенно ненужная абстракция.

ovangle 05.01.2016 10:34

Но все дело в библиотеках в абстракции. Наличие функции isNumber (на любом языке) очень помогает, потому что вы можете встроить ее прямо в операторы if и получить гораздо более читаемый и поддерживаемый код, который полагается на блоки try-catch. Кроме того, если вам нужно использовать код более одного раза в более чем одном классе / модуле, вы использовали больше строк кода, чем было бы у встроенной функции.

JamEngulfer 18.03.2016 14:19

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

Ваши доллары "2e-2" тоже являются плавающими (дополнительный аргумент в пользу использования числа с плавающей запятой :)

tzot 10.12.2008 01:59

@tzot НИКОГДА не используйте число с плавающей запятой для представления денежной стоимости.

Luke 07.11.2012 19:25

@Luke: Я полностью согласен с вами, хотя я никогда не предлагал использовать числа с плавающей запятой для представления денежных значений; Я только что сказал, что денежные значения может должны быть представлены как числа с плавающей запятой :)

tzot 08.11.2012 15:19

Which, not only is ugly and slow, seems clunky.

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

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

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

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

Другое распространенное место, где Python использует исключения для основных функций, - это hasattr(), который представляет собой просто вызов getattr(), заключенный в try/except. Тем не менее, обработка исключений медленнее, чем обычное управление потоком, поэтому использование ее для чего-то, что будет истинным большую часть времени, может привести к снижению производительности.

kindall 10.06.2011 21:50

Кажется, что если вы хотите однострочник, вы SOL

Basic 10.03.2014 15:21

Также питонизмом является идея о том, что «лучше просить прощения, чем разрешения», относительно влияния дешевых исключений.

heltonbiker 26.04.2016 04:20

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

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

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

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

DarwinSurvivor 24.07.2013 09:39

Обновлено после того, как Альфе указал, что вам не нужно отдельно проверять 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

Я не согласен. Это ОЧЕНЬ маловероятно при нормальном использовании, и вам будет лучше создать вызов is_complex_number (), когда вы их используете, чем обременять вызов дополнительной операцией для 0,0001% вероятности неправильной работы.

Jiminion 25.07.2013 18:43

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

Alfe 22.04.2016 12:31

Эта функция вернет значения NaN и Inf Pandas в виде числовых значений.

fixxxer 29.05.2016 14:51
complex('(01989)') вернет (1989+0j). Но float('(01989)') выйдет из строя. Поэтому я считаю, что использование complex - не лучшая идея.
plhn 20.12.2018 18:19
Ой. Странно, что complex() принимает синтаксис с разделителями ( и ) - предположительно для учета сложения составных векторов в мнимой плоскости, лежащей в основе комплексных чисел, но все же. Как предполагает @plhn, использование здесь complex() приводит к ложным срабатываниям. Не делайте этого в производственном коде. Честно говоря, s.lstrip('-').replace('.','',1).replace('e-','',1).replace('‌​e','',1).isdigit() остается оптимальным решением для большинства случаев использования.
Cecil Curry 25.09.2020 04:07

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

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

>>> float('NaN')
nan

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

ГРАММ.

На самом деле, NaN может быть хорошим значением для возврата (а не False), если переданный текст на самом деле не является представлением числа. Проверка на это - своего рода боль (для типа Python float действительно нужен метод), но вы можете использовать его в вычислениях, не вызывая ошибок, и вам нужно только проверить результат.

kindall 10.06.2011 21:50

Еще одно исключение - строка 'inf'. Либо inf, либо NaN также могут иметь префикс + или - и по-прежнему приниматься.

agf 23.05.2012 03:10

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

RyanN 16.03.2013 00:29
x-1 == x верен для больших поплавков, меньших, чем inf. Начиная с Python 3.2, вы можете использовать math.isfinite для проверки чисел, которые не являются ни NaN, ни бесконечными, или проверить и math.isnan, и math.isinf до этого.
Steve Jessop 22.01.2014 22:39

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

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

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

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

float.parse ():

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

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

float.try_parse ():

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

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

Чтобы расширить float, включив в него parse () и try_parse (), вам нужно обезвредить класс 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

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

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

Evan Plaice 18.02.2012 05:37

Чтобы добавить поддержку комплексных чисел, см. Ответ @Matthew Wilcoxson. stackoverflow.com/a/3335060/290340.

Evan Plaice 18.02.2012 05:47

Использование ! вместо not может быть незначительной ошибкой, но вы определенно не можете назначать атрибуты встроенному float в CPython.

BlackJack 28.08.2016 14:34

проголосовали против за перехват всех исключений без разбора и за использование несуществующего ключевого слова "throw"

Janus Troelsen 07.09.2020 23:54

Итак, чтобы собрать все вместе, проверяя 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

Пока лучший ответ. Спасибо

anish 15.01.2020 15:06

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

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

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

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

вернет ложь

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

Однако это не учитывает отрицательные числа.

Michael Barton 24.10.2014 01:33

Или числа с показателями, например 1.234e56 (которые также могут быть записаны как +1.234E+56 и еще несколько вариантов).

Alfe 22.04.2016 12:29
re.match(r'^[+-]*(0[xbo])?[0-9A-Fa-f]*\.?[0-9A-Fa-f]*(E[+-]*‌​[0-9A-Fa-f]+)$', 'str') должен лучше определять число (но не все, я этого не утверждаю). Я не рекомендую использовать это, гораздо лучше использовать исходный код Вопросника.
Baldrickk 09.02.2017 18:31

если вам не нравится это решение, прочтите это перед голосованием против!

aloisdg 23.02.2018 12:32

чувак, это самое умное решение, которое я когда-либо видел на этом сайте !, молодец!

Karam Qusai 06.12.2019 13:26

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

Вы также должны проверить производительность на недопустимые случаи. С этими числами не возникает никаких исключений, это как раз «медленная» часть.

Ugo Méda 28.01.2013 18:17

@ UgoMéda я последовал твоему совету из 2013 года и сделал это :)

Ron Reiter 28.04.2018 18:27

«Обратите внимание, что проверка успешного приведения - единственный точный метод» <- на самом деле это не так. Я провел ваш тест, используя регулярное выражение в моем ответе выше, и он действительно работает быстрее, чем регулярное выражение. Я добавлю результаты к своему ответу выше.

David Ljung Madison Stellar 29.01.2020 02:05

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

David Ljung Madison Stellar 29.01.2020 02:15

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

для неотрицательных int это нормально ;-)

andilabs 22.03.2014 17:10
s.isdecimal() проверяет, является ли строка s неотрицательным целым числом. s.isnumeric() включает символы, которые int() отклоняет.
jfs 19.10.2014 09:29

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

RyanN предлагает

If you want to return False for a NaN and Inf, change line to x = float(s); return (x == x) and (x - 1 != x). This should return True for all floats except Inf and NaN

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

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

за красивые графики +1. Я видел тест и видел график, все вещи TL; DR стали ясными и интуитивно понятными.

jcchuks 18.11.2016 21:35

Я согласен с @JCChuks: график очень помогает быстро получить все TL; DR. Но я думаю, что TL; DR (например: TL; DR: лучшее решение - s.replace('.','',1).isdigit()) должен появиться в начале этого ответа. В любом случае он должен быть принятым. Спасибо!

Simon C. 10.03.2017 12:59

TLDR вводит в заблуждение и лукавит. Быть «лучшим» не коррелирует ни с одним тестом производительности. Например, я обычно ценю удобочитаемость намного больше, чем микрооптимизации, поэтому тесты почти не имеют значения при определении лучшего решения для моего контекста. TL; DR был бы более точным, если бы это было сказано: «Лучше всего, если оценивать по времени выполнения из небольшого набора произвольных тестов».

Corey Goldberg 28.04.2018 00:10

честно говоря, но в TLDR я также не сказал, что он основан на тестах. Мне также кажется, что это наиболее удобочитаемое решение.

user2489252 29.04.2018 00:34

Обратите внимание, что добавление .lstrip('-') для отрицательных чисел увеличивает время работы функции is_number_repl_isdigit в 1,5 раза.

Alexander McFarlane 22.08.2018 12:23

Можете ли вы включить fastnumbers в график (см. stackoverflow.com/a/25299619/1399279, чтобы узнать, как использовать его в этом приложении)?

SethMMorton 22.08.2018 19:49

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

Urchin 10.04.2019 18:55

Важно отметить, что даже если предположить, что тире быть не может, метод replace-isdigit работает быстрее только для нечисловых (ложный результат), а метод try-except быстрее для чисел (истинный результат). Если большая часть введенных вами данных является допустимой, вам лучше воспользоваться решением try-except!

Markus von Broady 24.04.2019 15:43

Не работает с экспоненциальной записью, такой как '1.5e-9', или с негативами.

EL_DON 17.10.2019 22:03

Отлично, сделал что-то сопоставимое, без хороших диаграмм, но потом тысячи итераций. Когда я запускал намного больше случаев, try / catch становился немного дороже в отрицательных случаях, чем регулярное выражение, но при использовании непосредственно в if (if test_trycatch_function (x): ... else: ...) потребовалось двойное время регулярного выражения. Мои познания в Python не так уж глубоки, поэтому я не понимаю, зачем просто запускать или присваивать его переменной, которая больше не используется, я не знаю. Может, какой-то оптимизатор его полностью пропускает?

benzhi 17.03.2020 19:06
Блестящий,, за исключением очевидных предупреждений о ложных отрицаниях для возведения в степень и отрицательных значений, которые вы можете тривиально исправить, просто связав вызовы s.replace(). Например, s.replace('.','',1).replace('e-','',1).replace('e','',1).isd‌​igit() обрабатывает возведение в степень. Чтобы затем обработать негативы, просто удалите первый символ слева, если это тире. Например, s.lstrip('-').replace('.','',1).replace('e-','',1).replace('‌​e','',1).isdigit(). Да, я исчерпывающе протестировал этот однострочник и могу подтвердить, что он ведет себя так, как ожидалось.
Cecil Curry 25.09.2020 03:59

Вы должны терпимо относиться к пустому пространству и принимать знак, поэтому comp = re_compile("^\s*[+-]?\d+?\.\d+?\s*$").

Hans Ginzel 30.10.2020 16:32

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

Для строк, не являющихся числами, try: except: на самом деле медленнее, чем регулярные выражения. Для строк действительных чисел регулярное выражение работает медленнее. Итак, подходящий метод зависит от вашего ввода.

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

Я поправляюсь: -} просто не похоже, что он это делал. Возможно, использование таких имен, как prep_code_basis и prep_code_re_method, предотвратило бы мою ошибку.

Alfe 22.04.2016 23:11

Не могли бы вы объяснить, как работает ваш модуль, хотя бы для функции isfloat?

Solomon Ucko 05.05.2016 02:33

@SolomonUcko Вот ссылка на исходный код для части проверки строк: github.com/SethMMorton/fastnumbers/blob/v1.0.0/src/…. По сути, он проходит по каждому символу в строке по порядку и проверяет, что он следует шаблону для действительного числа с плавающей запятой. Если ввод уже является числом, он просто использует быстрый PyFloat_Check.

SethMMorton 05.05.2016 03:15

Протестировано с лучшими альтернативами в этом потоке, я подтверждаю, что это решение безусловно самое быстрое. Второй самый быстрый метод - str(s).strip('-').replace('.','',1).isdigit(), который примерно в 10 раз медленнее!

Alexander McFarlane 22.08.2018 12:59

Обратите внимание, что timeit.timeit запускает оператор 1 миллион раз. Я был сбит с толку, почему эти цифры казались такими медленными.

mic 13.10.2020 01:58

Это отличное решение, и, честно говоря, оно должно быть ближе к вершине. Для этого действительно требуется новая библиотека, но она проста в использовании и работает интуитивно понятно. Было именно то, что я искал. Спасибо @SethMMorton

rfadams 05.02.2021 03:06

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

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

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

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

Не отвечает is_number('10')

geotheory 18.08.2015 23:23

@geotheory, что значит "не отвечает"?

Solomon Ucko 05.05.2016 02:38

Для 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

Не работает с такими вещами, как 1.234e56 и т.п. Кроме того, мне было бы интересно, как вы узнали, что 99999999999999999999e99999999999999999999 - это не число. Попытка разобрать это быстро выясняет.

Alfe 22.04.2016 12:37

Это работает примерно на 30% быстрее, чем принятое решение для списка из 50 метров строк и на 150% быстрее для списка из 5 тысяч строк. ?

Zev Averbach 21.02.2017 16:59

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

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

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

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

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

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

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

Хотя для дробей вам, вероятно, нужно выполнить x.replace('/','',1).isdigit(), иначе даты, такие как 4/7/2017, будут ошибочно интерпретированы как числа.

Yuxuan Chen 07.04.2017 17:06

Лучший способ связать условия: stackoverflow.com/q/3411771/5922329

Daniel Braun 11.04.2018 17:14

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

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

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

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

  • Положительное число
  • Положительный / отрицательный - целое / с плавающей запятой
  • Как отбросить строки "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 сравнивается с самим собой. Например:

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

У меня аналогичная проблема. Вместо определения функции 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]
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

Вы не считаете, что 1e6 представляет собой число?

Mark Dickinson 02.08.2018 15:42

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

a = "50"b=50c=50.1d = "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

что такое аст?


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

что такое "ast"?

user10460842 06.10.2018 20:30

на виду на типах

Walter 08.01.2021 04:17

Это не удается при тестировании is_numeric("String 1"). Обернул метод в try / except и работает.

Ramon 10.01.2021 07:53

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

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

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

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

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

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

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

# 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

Надеюсь, что это правда - хотелось бы услышать о любых контрпримерах. :)

David Ljung Madison Stellar 11.05.2019 00:18

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

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)])
def is_float(s):
    if s is None:
        return False

    if len(s) == 0:
        return False

    digits_count = 0
    dots_count = 0
    signs_count = 0

    for c in s:
        if '0' <= c <= '9':
            digits_count += 1
        elif c == '.':
            dots_count += 1
        elif c == '-' or c == '+':
            signs_count += 1
        else:
            return False

    if digits_count == 0:
        return False

    if dots_count > 1:
        return False

    if signs_count > 1:
        return False

    return True

str.isnumeric()

Return True if all characters in the string are numeric characters, and there is at least one character, False otherwise. Numeric characters include digit characters, and all characters that have the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH. Formally, numeric characters are those with the property value Numeric_Type=Digit, Numeric_Type=Decimal or Numeric_Type=Numeric.

str.isdecimal()

Return True if all characters in the string are decimal characters and there is at least one character, False otherwise. Decimal characters are those that can be used to form numbers in base 10, e.g. U+0660, ARABIC-INDIC DIGIT ZERO. Formally a decimal character is a character in the Unicode General Category “Nd”.

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

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

Извините за сообщение в ветке 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

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

Другие вопросы по теме