Как лучше всего проверить, может ли строка быть представлена в виде числа в Python?
В настоящее время у меня есть следующая функция:
def is_number(s):
try:
float(s)
return True
except ValueError:
return False
Что не только некрасиво и медленно, но и кажется неуклюжим. Однако я не нашел лучшего метода, потому что вызов float в основной функции еще хуже.
И вам не нужно просто возвращать True или False. Вместо этого вы можете вернуть значение, измененное соответствующим образом - например, вы можете использовать это, чтобы заключить нечисловые значения в кавычки.
Не лучше ли вернуть результат float (s) в случае успешного преобразования? У вас все еще есть проверка на успех (результат - Ложь), и у вас действительно есть преобразование, которое вы, вероятно, в любом случае захотите.
Thruston - я понимаю вашу точку зрения, но тогда проверка менее тривиальна.
Несмотря на то, что этот вопрос более старый, я просто хотел сказать, что это элегантный способ, который задокументирован как EAFP. Так что, вероятно, лучшее решение для такого рода проблем.
Это кажется нормальным, если вы не проверяете вводимые пользователем данные, поскольку locale.atoi ("0,1,00") оценивается как 100 ....
Очень полезная функция. Кроме того, если вы хотите разрешить пробел, например 1e + 2 и т. д., Эту функцию необходимо изменить.
Если вы не знаете, является ли входное значение строкой, вы также можете поймать TypeError
Возвращает результат float(s) в случае успеха или None в случае неудачи. Тогда вы получите поведение True / False, а также сможете напрямую использовать результат.
связанные: Извлечь значение с плавающей запятой / двойное значение
x = float('0.00'); if x: use_float(x);, у вас теперь есть ошибка в вашем коде. Истинные значения являются причиной того, что эти функции вызывают исключение, а не возвращают None. Лучшее решение - просто избегать служебной функции и окружать вызов float в try catch, когда вы хотите его использовать.
Это часть проблемы, рассмотренной в сообщении stackoverflow.com/questions/36903462/adding-numbers-in-a-string /…
Предупреждение: во фрагменте говорится, что объект Любые, автоматически переводящий бросает в положение с плавающей точкой, является числом, и это может вводить в заблуждение. Например, простой результат bool будет числом, потому что float (True) возвращает действительное значение 1.0.
не медленный. int (s) или float (s), вероятно, почти так же быстро, как то, что интерпретатор python использует для таких вещей, и может даже иметь под собой некоторый код C. In [17]: time_it (int, '333', count = 1) Out [17]: 4.0531158447265625e-06 Чертовски быстро.
Вы, вероятно, захотите избавиться от части ValueError, иначе это вызовет исключение, когда получит список / dict для ввода






Если вы ищете синтаксический анализ (положительные, беззнаковые) целые числа вместо чисел с плавающей запятой, вы можете использовать функцию isdigit() для строковых объектов.
>>> a = "03523"
>>> a.isdigit()
True
>>> b = "963spam"
>>> b.isdigit()
False
Строковые методы - isdigit(): Python2, Python3
Также есть кое-что о строках Unicode, с которыми я не слишком знаком Юникод - десятичный / десятичный
Это отрицательно и на негативах
Не работает и с экспонентами: '1e3'.isdigit () -> False
Хотя Number! = Digit, люди, которые ищут способы проверить, содержит ли строка целое число, вполне могут натолкнуться на этот вопрос, и подход isDigit вполне может быть идеально подходящим для их приложения.
Даже если этот ответ не решает вопрос OP, чтобы решить проблему с поплавками, как насчет того, чтобы сделать что-то вроде a.isdigit () или a.replace ('.', ''). Isdigit ()?
@AdamParkin: isdigit() и int() имеют разные мнения о том, что такое целое число, например, для символа Unicode u'\u00b9': u'¹'.isdigit() - это True, но int(u'¹') вызывает ValueError.
Название isdigit вводит в заблуждение с самого начала, так как цифра означает [0-9].
+1: isdigit () может быть не тем, что искал OP, но это именно то, что я хотел. Возможно, этот ответ и метод не охватывают все типы чисел, но он по-прежнему очень актуален, вопреки аргументам о его точности. Хотя «Число! = Цифра», цифра по-прежнему является подмножеством числа, особенно чисел, которые являются положительными, неотрицательными и используют основание 1–10. Кроме того, этот метод особенно полезен и краток для случаев, когда вы хотите проверить, является ли строка числовым идентификатором или нет, который часто попадает в подмножество чисел, которое я только что описал.
@JustinJohnson: ты читал мой предыдущий комментарий? Вы, вероятно, захотите isdecimal() вместо.
@ J.F.Sebastian Вы правы; isdecimal() - правильный метод для использования в описанном мной сценарии.
+1, я искал это решение на основе моего запроса Google, поэтому любой, кто сказал, что этот ответ неуместен, не думал ни о ком, кроме OP. Поскольку у переполнения стека так много ответов, которые появляются в Google, это абсолютно актуально для тех, кто ищет этот тип решения (например, если вам нужно удалить любые нецифровые цифры из номера телефона: phone = ''.join([n for n in someString if n.isdigit()]))
Как у этого есть 800+ голосов, когда это совершенно неправильно? Тот факт, что здесь есть комментарии вроде «+1, это не ответ на вопрос, но все равно помогает мне», поражает меня. -1.
@DuckPuncher: для телефонных номеров вам нужен isdecimal() вместо isdigit() (если someString может содержать символы, отличные от ascii).
Это бомба на отрицательных числах, которые являются числами, о которых спрашивал ОП (ОП никогда не указывал положительные).
Как говорили другие, это хороший метод, но совершенно не подходит для вопроса. В противном случае люди захотят отметить мой ответ «курица» как правильный. Это то, что я ел на ужин вчера вечером, и поэтому он верен и верен, просто не имеет отношения к заданному вопросу. Если серьезно, да, этот метод - хороший метод, но он совершенно неверен для заданного вопроса, который конкретно ссылается на плавает, и поэтому за него не следует голосовать.
@ Jason9987 цифра - это один из 10 символов [0-9]. Так что математические определения здесь все равно не сработают.
Вы можете разделить на '.' и проверьте, являются ли обе половины is_digit (), чтобы проверить число с плавающей запятой.
Which, not only is ugly and slow
Я бы не согласился с обоими.
Регулярное выражение или другой метод синтаксического анализа строк будет уродливее и медленнее.
Я не уверен, что что-то намного может быть быстрее, чем указано выше. Он вызывает функцию и возвращает ее. Try / Catch не вызывает особых накладных расходов, поскольку наиболее частое исключение выявляется без тщательного поиска кадров стека.
Проблема в том, что любая функция числового преобразования дает два вида результатов.
C (в качестве примера) пытается обойти это несколькими способами. Python излагает это четко и ясно.
Я думаю, что ваш код для этого идеален.
Я не думаю, что код идеален (но я думаю, что он очень близок): чаще всего помещают Только «тестируемую» часть в предложение try, поэтому я бы поместил return True в пункт elsetry . Одна из причин заключается в том, что с кодом в вопросе, если бы мне пришлось его просмотреть, мне пришлось бы проверить, что второй оператор в предложении try не может вызвать ValueError: конечно, это не требует слишком много времени или мощности мозга , но зачем использовать их, когда они не нужны?
Ответ кажется убедительным, но заставляет меня задаться вопросом, почему он не предоставляется прямо из коробки ... Я скопирую его и буду использовать в любом случае.
Как ужасно. Как насчет того, что мне все равно, что такое число является, только то, что это число (которое привело меня сюда)? Вместо однострочного IsNumeric() я получаю либо try / catch, либо другую упаковку try / catch. фу
@Basic Я не понимаю твоей точки зрения. Назовите вашу функцию, которая выполняет проверку IsNumeric, и используйте эту функцию. Это идея использования функций - однострочные.
@Nils Я хочу сказать, что это настолько очевидная и простая операция, доступная во всех других языках высокого уровня, которые я использовал, что ее отсутствие кажется вопиющим упущением. С другой стороны, здесь не место для затяжных дискуссий, так что давайте согласимся не соглашаться.
@Basic - «[Проверка того, является ли строка числом] доступна на всех других языках высокого уровня» - я согласен с вами по большей части предложения, из которого я извлек эту цитату, но я не согласен с цитируемым текстом. Доступен ли он на Java (и если да, то с какой версии JDK?) Последний раз я проверял (по общему признанию, несколько лет назад), не было.
@ArtOfWarfare Ключевой момент - это то, где я сказал: «То, что я использовал» ... Не имея намерения начать войну, я по возможности избегаю Java. Отсутствие IsNumeric() меня совсем не удивляет.
@Basic - Мне любопытно, какие языки вы использовали с этой функцией из коробки? Мы рассмотрели, что у Python и Java его нет, и если в Java его нет, мы можем исключить C, C++ и, возможно, C# тоже. В Objective-C этого нет. Осталось не так много популярных языков высокого уровня ... есть ли он в Ruby? Есть ли это в PHP? Perl? На данный момент я думаю, что я назвал все популярные / основные языки высокого уровня ...
@ArtOfWarfare PHP, Javascript и VB.Net в моей голове. В T-SQL есть ISNUMERIC(), если вы отнесете это к языку. В C# есть Double.TryParse(), который возвращает логическое значение, хотя он может быть немного более нечетким (может опционально разрешать пробелы, разделители тысяч и т. д.). В любом случае, мы перехватываем эту ветку комментариев, поэтому я вернусь и удалю свои сегодняшние комментарии через несколько часов.
@Basic - Ах, я пренебрегал JS. SQL - настолько узконаправленный язык, что я бы не стал сравнивать его с Python или любыми другими языками программирования общего назначения высокого уровня. И я должен признаться, что не знаком с PHP, VB или C#. Ваши комментарии достаточно справедливы. Я не вижу смысла их удалять.
Он не предоставляется «из коробки», потому что if is_number(s): x = float(x) else: // fail имеет то же количество строк кода, что и try: x = float(x) catch TypeError: # fail. Эта функция полезности - совершенно ненужная абстракция.
Но все дело в библиотеках в абстракции. Наличие функции isNumber (на любом языке) очень помогает, потому что вы можете встроить ее прямо в операторы if и получить гораздо более читаемый и поддерживаемый код, который полагается на блоки try-catch. Кроме того, если вам нужно использовать код более одного раза в более чем одном классе / модуле, вы использовали больше строк кода, чем было бы у встроенной функции.
Преобразование в float и перехват ValueError, вероятно, самый быстрый способ, поскольку float () специально предназначен для этого. Все остальное, что требует синтаксического анализа строк (регулярное выражение и т. д.), Скорее всего, будет медленнее из-за того, что оно не настроено для этой операции. Мои 0,02 доллара.
Ваши доллары "2e-2" тоже являются плавающими (дополнительный аргумент в пользу использования числа с плавающей запятой :)
@tzot НИКОГДА не используйте число с плавающей запятой для представления денежной стоимости.
@Luke: Я полностью согласен с вами, хотя я никогда не предлагал использовать числа с плавающей запятой для представления денежных значений; Я только что сказал, что денежные значения может должны быть представлены как числа с плавающей запятой :)
Which, not only is ugly and slow, seems clunky.
Может потребоваться некоторое привыкание, но это питонический способ сделать это. Как уже указывалось, альтернативы хуже. Но есть еще одно преимущество такого подхода: полиморфизм.
Центральная идея утиного набора текста заключается в том, что «если он ходит и говорит как утка, значит, это утка». Что, если вы решите, что вам нужно создать подкласс строки, чтобы вы могли изменить способ определения, можно ли что-то преобразовать в число с плавающей запятой? Или что, если вы решите полностью протестировать какой-то другой объект? Вы можете делать это, не меняя приведенный выше код.
Другие языки решают эти проблемы с помощью интерфейсов. Я сохраню анализ того, какое решение лучше для другой темы. Дело, однако, в том, что python явно находится на стороне утиного ввода в уравнении, и вам, вероятно, придется привыкнуть к подобному синтаксису, если вы планируете много программировать на Python (но это не значит, что конечно должно нравиться).
Еще одна вещь, которую вы, возможно, захотите принять во внимание: Python довольно быстро генерирует и перехватывает исключения по сравнению с множеством других языков (например, в 30 раз быстрее, чем .Net). Черт возьми, сам язык даже выдает исключения, чтобы сообщить неисключительные, нормальные условия программы (каждый раз, когда вы используете цикл for). Таким образом, я бы не стал слишком беспокоиться об аспектах производительности этого кода, пока вы не заметите серьезную проблему.
Другое распространенное место, где Python использует исключения для основных функций, - это hasattr(), который представляет собой просто вызов getattr(), заключенный в try/except. Тем не менее, обработка исключений медленнее, чем обычное управление потоком, поэтому использование ее для чего-то, что будет истинным большую часть времени, может привести к снижению производительности.
Кажется, что если вы хотите однострочник, вы SOL
Также питонизмом является идея о том, что «лучше просить прощения, чем разрешения», относительно влияния дешевых исключений.
Вот мой простой способ сделать это. Допустим, я просматриваю несколько строк и хочу добавить их в массив, если они окажутся числами.
try:
myvar.append( float(string_to_check) )
except:
continue
Замените myvar.apppend любой операцией, которую вы хотите выполнить со строкой, если она оказывается числом. Идея состоит в том, чтобы попытаться использовать операцию float () и использовать возвращенную ошибку, чтобы определить, является ли строка числом.
Вы должны переместить добавляемую часть этой функции в оператор else, чтобы избежать случайного запуска исключения, если с массивом что-то не так.
Обновлено после того, как Альфе указал, что вам не нужно отдельно проверять 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% вероятности неправильной работы.
Вы можете полностью удалить содержимое float() и просто проверить успешность вызова complex(). Все, что проанализировано float(), может быть проанализировано complex().
Эта функция вернет значения NaN и Inf Pandas в виде числовых значений.
complex('(01989)') вернет (1989+0j). Но float('(01989)') выйдет из строя. Поэтому я считаю, что использование complex - не лучшая идея.
complex() принимает синтаксис с разделителями ( и ) - предположительно для учета сложения составных векторов в мнимой плоскости, лежащей в основе комплексных чисел, но все же. Как предполагает @plhn, использование здесь complex() приводит к ложным срабатываниям. Не делайте этого в производственном коде. Честно говоря, s.lstrip('-').replace('.','',1).replace('e-','',1).replace('e','',1).isdigit() остается оптимальным решением для большинства случаев использования.
Есть одно исключение, которое вы можете принять во внимание: строка NaN.
Если вы хотите, чтобы is_number возвращал FALSE для 'NaN', этот код не будет работать, поскольку Python преобразует его в свое представление числа, которое не является числом (поговорим о проблемах с идентификацией):
>>> float('NaN')
nan
В противном случае я должен поблагодарить вас за фрагмент кода, который я сейчас широко использую. :)
ГРАММ.
На самом деле, NaN может быть хорошим значением для возврата (а не False), если переданный текст на самом деле не является представлением числа. Проверка на это - своего рода боль (для типа Python float действительно нужен метод), но вы можете использовать его в вычислениях, не вызывая ошибок, и вам нужно только проверить результат.
Еще одно исключение - строка 'inf'. Либо inf, либо NaN также могут иметь префикс + или - и по-прежнему приниматься.
Если вы хотите вернуть False для NaN и Inf, измените строку на x = float (s); return (x == x) и (x - 1! = x). Это должно вернуть True для всех чисел с плавающей запятой, кроме Inf и NaN.
x-1 == x верен для больших поплавков, меньших, чем inf. Начиная с Python 3.2, вы можете использовать math.isfinite для проверки чисел, которые не являются ни NaN, ни бесконечными, или проверить и math.isnan, и math.isinf до этого.
Я сделал тест на скорость. Допустим, если строка вероятный является числом, стратегия попробовать / кроме является наиболее быстрой из возможных. Если строка скорее всего, не является числом а также, вас интересует проверка Целое число, стоит провести некоторый тест (цифра плюс заголовок '-' ). Если вы хотите проверить число с плавающей запятой, вы должны использовать код попробовать / кроме без выхода.
В C# есть две разные функции, которые обрабатывают синтаксический анализ скалярных значений:
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 и на самом деле не тестировал это, поэтому могут быть некоторые незначительные ошибки. Если увидите, не стесняйтесь исправлять мои ошибки.
Чтобы добавить поддержку комплексных чисел, см. Ответ @Matthew Wilcoxson. stackoverflow.com/a/3335060/290340.
Использование ! вместо not может быть незначительной ошибкой, но вы определенно не можете назначать атрибуты встроенному float в CPython.
проголосовали против за перехват всех исключений без разбора и за использование несуществующего ключевого слова "throw"
Итак, чтобы собрать все вместе, проверяя 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
Пока лучший ответ. Спасибо
как насчет этого:
'3.14'.replace('.','',1).isdigit()
который вернет истину только в том случае, если он есть или нет '.' в строке цифр.
'3.14.5'.replace('.','',1).isdigit()
вернет ложь
редактировать: только что увидел еще один комментарий ...
можно добавить .replace(badstuff,'',maxnum_badstuff) для других случаев. если вы передаете соль, а не произвольные приправы (ref: xkcd # 974), это подойдет: P
Однако это не учитывает отрицательные числа.
Или числа с показателями, например 1.234e56 (которые также могут быть записаны как +1.234E+56 и еще несколько вариантов).
re.match(r'^[+-]*(0[xbo])?[0-9A-Fa-f]*\.?[0-9A-Fa-f]*(E[+-]*[0-9A-Fa-f]+)$', 'str') должен лучше определять число (но не все, я этого не утверждаю). Я не рекомендую использовать это, гораздо лучше использовать исходный код Вопросника.
если вам не нравится это решение, прочтите это перед голосованием против!
чувак, это самое умное решение, которое я когда-либо видел на этом сайте !, молодец!
Я хотел посмотреть, какой метод самый быстрый. В целом наилучшие и наиболее стабильные результаты дает функция 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
Вы также должны проверить производительность на недопустимые случаи. С этими числами не возникает никаких исключений, это как раз «медленная» часть.
@ UgoMéda я последовал твоему совету из 2013 года и сделал это :)
«Обратите внимание, что проверка успешного приведения - единственный точный метод» <- на самом деле это не так. Я провел ваш тест, используя регулярное выражение в моем ответе выше, и он действительно работает быстрее, чем регулярное выражение. Я добавлю результаты к своему ответу выше.
Кстати, забавно, что ваш создатель плохих чисел действительно может создавать некоторые допустимые числа, хотя это бывает довольно редко. :)
Вы можете использовать строки 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 это нормально ;-)
s.isdecimal() проверяет, является ли строка s неотрицательным целым числом. s.isnumeric() включает символы, которые int() отклоняет.
Вы можете обобщить технику исключения полезным способом, вернув больше полезных значений, чем 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: график очень помогает быстро получить все TL; DR. Но я думаю, что TL; DR (например: TL; DR: лучшее решение - s.replace('.','',1).isdigit()) должен появиться в начале этого ответа. В любом случае он должен быть принятым. Спасибо!
TLDR вводит в заблуждение и лукавит. Быть «лучшим» не коррелирует ни с одним тестом производительности. Например, я обычно ценю удобочитаемость намного больше, чем микрооптимизации, поэтому тесты почти не имеют значения при определении лучшего решения для моего контекста. TL; DR был бы более точным, если бы это было сказано: «Лучше всего, если оценивать по времени выполнения из небольшого набора произвольных тестов».
честно говоря, но в TLDR я также не сказал, что он основан на тестах. Мне также кажется, что это наиболее удобочитаемое решение.
Обратите внимание, что добавление .lstrip('-') для отрицательных чисел увеличивает время работы функции is_number_repl_isdigit в 1,5 раза.
Можете ли вы включить fastnumbers в график (см. stackoverflow.com/a/25299619/1399279, чтобы узнать, как использовать его в этом приложении)?
Этот метод не обрабатывает отрицательные числа (тире). Я бы посоветовал просто использовать метод с плавающей запятой, поскольку он менее подвержен ошибкам и будет работать каждый раз.
Важно отметить, что даже если предположить, что тире быть не может, метод replace-isdigit работает быстрее только для нечисловых (ложный результат), а метод try-except быстрее для чисел (истинный результат). Если большая часть введенных вами данных является допустимой, вам лучше воспользоваться решением try-except!
Не работает с экспоненциальной записью, такой как '1.5e-9', или с негативами.
Отлично, сделал что-то сопоставимое, без хороших диаграмм, но потом тысячи итераций. Когда я запускал намного больше случаев, try / catch становился немного дороже в отрицательных случаях, чем регулярное выражение, но при использовании непосредственно в if (if test_trycatch_function (x): ... else: ...) потребовалось двойное время регулярного выражения. Мои познания в Python не так уж глубоки, поэтому я не понимаю, зачем просто запускать или присваивать его переменной, которая больше не используется, я не знаю. Может, какой-то оптимизатор его полностью пропускает?
s.replace(). Например, s.replace('.','',1).replace('e-','',1).replace('e','',1).isdigit() обрабатывает возведение в степень. Чтобы затем обработать негативы, просто удалите первый символ слева, если это тире. Например, s.lstrip('-').replace('.','',1).replace('e-','',1).replace('e','',1).isdigit(). Да, я исчерпывающе протестировал этот однострочник и могу подтвердить, что он ведет себя так, как ожидалось.Вы должны терпимо относиться к пустому пространству и принимать знак, поэтому comp = re_compile("^\s*[+-]?\d+?\.\d+?\s*$").
Мне нужно было определить, преобразуется ли строка в базовые типы (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, предотвратило бы мою ошибку.
Не могли бы вы объяснить, как работает ваш модуль, хотя бы для функции isfloat?
@SolomonUcko Вот ссылка на исходный код для части проверки строк: github.com/SethMMorton/fastnumbers/blob/v1.0.0/src/…. По сути, он проходит по каждому символу в строке по порядку и проверяет, что он следует шаблону для действительного числа с плавающей запятой. Если ввод уже является числом, он просто использует быстрый PyFloat_Check.
Протестировано с лучшими альтернативами в этом потоке, я подтверждаю, что это решение безусловно самое быстрое. Второй самый быстрый метод - str(s).strip('-').replace('.','',1).isdigit(), который примерно в 10 раз медленнее!
Обратите внимание, что timeit.timeit запускает оператор 1 миллион раз. Я был сбит с толку, почему эти цифры казались такими медленными.
Это отличное решение, и, честно говоря, оно должно быть ближе к вершине. Для этого действительно требуется новая библиотека, но она проста в использовании и работает интуитивно понятно. Было именно то, что я искал. Спасибо @SethMMorton
Я работал над проблемой, которая привела меня к этой теме, а именно, как преобразовать набор данных в строки и числа наиболее интуитивно понятным способом. После прочтения исходного кода я понял, что то, что мне нужно, отличалось двумя способами:
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, что значит "не отвечает"?
Для 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 - это не число. Попытка разобрать это быстро выясняет.
Это работает примерно на 30% быстрее, чем принятое решение для списка из 50 метров строк и на 150% быстрее для списка из 5 тысяч строк. ?
Я знаю, что это особенно старый, но я бы добавил ответ, который, как мне кажется, охватывает информацию, отсутствующую в ответе с наибольшим количеством голосов, который может быть очень ценным для любого, кто найдет это:
Для каждого из следующих методов соедините их счетчиком, если вам нужно принять какой-либо ввод. (Предполагая, что мы используем голосовые определения целых чисел, а не 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, будут ошибочно интерпретированы как числа.
Лучший способ связать условия: stackoverflow.com/q/3411771/5922329
Я также использовал упомянутую вами функцию, но вскоре заметил, что такие строки, как «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')
Этот ответ содержит пошаговое руководство с функцией с примерами поиска строки:
Вы можете использовать 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
Вышеупомянутые функции вернут 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.
Следовательно, приведенное выше понимание необходимо как-то изменить, чтобы:
Я предлагаю решение, вдохновленное числовыми типами 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 представляет собой число?
Вход может быть следующим:
a = "50"b=50c=50.1d = "50.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
что такое аст?
используйте метод 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
определить значение int:
>>> isinstance("54", int)
False
>>> isinstance(54, int)
True
>>>
обнаружить поплавок:
>>> isinstance("45.1", float)
False
>>> isinstance(45.1, float)
True
что такое "ast"?
на виду на типах
Это не удается при тестировании is_numeric("String 1"). Обернул метод в try / except и работает.
Этот код обрабатывает экспоненты, числа с плавающей запятой и целые числа без использования регулярных выражений.
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
Надеюсь, что это правда - хотелось бы услышать о любых контрпримерах. :)
Вспомогательная функция пользователя:
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
Return
Trueif all characters in the string are numeric characters, and there is at least one character,Falseotherwise. 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.
Return
Trueif all characters in the string are decimal characters and there is at least one character,Falseotherwise. 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
Это число? Правда
Что не так с вашим текущим решением? Он короткий, быстрый и читаемый.