Проверка, может ли строка быть преобразована в float в Python
У меня есть некоторый код на Python, который просматривает список строк и, по возможности, преобразует их в целые числа или числа с плавающей запятой. Сделать это для целых чисел довольно просто.
if element.isdigit():
newelement = int(element)
Числа с плавающей запятой сложнее. Прямо сейчас я использую partition('.')
для разделения строки и проверки, чтобы убедиться, что одна или обе стороны являются цифрами.
partition = element.partition('.')
if (partition[0].isdigit() and partition[1] == '.' and partition[2].isdigit())
or (partition[0] == '' and partition[1] == '.' and partition[2].isdigit())
or (partition[0].isdigit() and partition[1] == '.' and partition[2] == ''):
newelement = float(element)
Это работает, но, очевидно, оператор if для этого немного медлителен. Другое решение, которое я рассмотрел, - это просто обернуть преобразование в блок try / catch и посмотреть, удастся ли оно, как описано в этом вопросе .
У кого-нибудь есть другие идеи? Мнения об относительных достоинствах раздела и подходах try / catch?
Переведено автоматически
Ответ 1
Я бы просто использовал..
try:
float(element)
except ValueError:
print "Not a float"
..это просто и работает. Обратите внимание, что он все равно выдаст OverflowError, если элемент равен, например, 1<<1024.
Другим вариантом может быть регулярное выражение:
import re
if re.match(r'^-?\d+(?:\.\d+)$', element) is None:
print "Not float"
Ответ 2
Метод Python3 для проверки float:
def is_float(element: any) -> bool:
#If you expect None to be passed:
if element is None:
return False
try:
float(element)
return True
except ValueError:
return False
Версия Python2 из приведенного выше: Как мне разобрать строку в float или int?
Всегда проводите модульное тестирование. Что является float, а что нет, может вас удивить:
Command to parse Is it a float? Comment
-------------------------------------- --------------- ------------
print(isfloat("")) False
print(isfloat("1234567")) True
print(isfloat("1_2_3.4")) True 123.4, underscores ignored
print(isfloat("NaN")) True nan is also float
print(isfloat("123.456")) True
print(isfloat("123.E4")) True
print(isfloat(".1")) True
print(isfloat("6.523537535629999e-07")) True
print(isfloat("6e777777")) True This is same as Inf
print(isfloat("-iNF")) True
print(isfloat("1.797693e+308")) True
print(isfloat("infinity")) True
print(isfloat("1,234")) False
print(isfloat("NULL")) False case insensitive
print(isfloat("NaNananana BATMAN")) False
print(isfloat(",1")) False
print(isfloat("123.EE4")) False
print(isfloat("infinity and BEYOND")) False
print(isfloat("12.34.56")) False Two dots not allowed.
print(isfloat("#56")) False
print(isfloat("56%")) False
print(isfloat("0E0")) True
print(isfloat("x86E0")) False
print(isfloat("86-5")) False
print(isfloat("True")) False Boolean is not a float.
print(isfloat(True)) True Boolean is a float
print(isfloat("+1e1^5")) False
print(isfloat("+1e1")) True
print(isfloat("+1e1.3")) False
print(isfloat("+1.3P1")) False
print(isfloat("-+1")) False
print(isfloat("(1)")) False brackets not interpreted
Пропускать исключения, подобные этому, плохо, потому что убивать канареек плохо, потому что метод float может завершиться неудачей по причинам, отличным от пользовательского ввода. Не используйте подобный код в критически важном программном обеспечении. Также python изменил свой контракт относительно того, какие строки unicode могут быть переведены в float, поэтому ожидайте, что это поведение этого кода изменится при основных обновлениях версии.
Ответ 3
'1.43'.replace('.','',1).isdigit()
который вернет значение true
только в том случае, если в строке цифр есть один '.' или его нет.
'1.4.3'.replace('.','',1).isdigit()
вернет false
'1.ww'.replace('.','',1).isdigit()
вернет false
Ответ 4
TL; DR:
- Если ваши входные данные в основном представляют собой строки, которые могут быть преобразованы в float, то
try: except:
метод является лучшим собственным методом Python. - Если ваши входные данные в основном представляют собой строки, которые не могут быть преобразованы в float, лучше использовать регулярные выражения или метод partition .
- Если вы 1) не уверены в своем вводе или вам нужно больше скорости и 2) не возражаете и можете установить стороннее расширение C, fastnumbers работает очень хорошо.
Существует другой метод, доступный через сторонний модуль под названием fastnumbers (раскрытие информации, я автор); он предоставляет функцию под названием isfloat . Я взял самый простой пример, описанный Джейкобом Габриэлсоном в этом ответе, но добавил fastnumbers.isfloat
метод. Я должен также отметить, что пример Джейкоба не соответствовал параметру regex должным образом, потому что большая часть времени в этом примере была потрачена на глобальный поиск из-за оператора dot ... Я модифицировал эту функцию, чтобы дать более справедливое сравнение с try: except:
.
def is_float_try(str):
try:
float(str)
return True
except ValueError:
return False
import re
_float_regexp = re.compile(r"^[-+]?(?:\b[0-9]+(?:\.[0-9]*)?|\.[0-9]+\b)(?:[eE][-+]?[0-9]+\b)?$").match
def is_float_re(str):
return True if _float_regexp(str) else False
def is_float_partition(element):
partition=element.partition('.')
if (partition[0].isdigit() and partition[1]=='.' and partition[2].isdigit()) or (partition[0]=='' and partition[1]=='.' and partition[2].isdigit()) or (partition[0].isdigit() and partition[1]=='.' and partition[2]==''):
return True
else:
return False
from fastnumbers import isfloat
if __name__ == '__main__':
import unittest
import timeit
class ConvertTests(unittest.TestCase):
def test_re_perf(self):
print
print 're sad:', timeit.Timer('ttest.is_float_re("12.2x")', "import ttest").timeit()
print 're happy:', timeit.Timer('ttest.is_float_re("12.2")', "import ttest").timeit()
def test_try_perf(self):
print
print 'try sad:', timeit.Timer('ttest.is_float_try("12.2x")', "import ttest").timeit()
print 'try happy:', timeit.Timer('ttest.is_float_try("12.2")', "import ttest").timeit()
def test_fn_perf(self):
print
print 'fn sad:', timeit.Timer('ttest.isfloat("12.2x")', "import ttest").timeit()
print 'fn happy:', timeit.Timer('ttest.isfloat("12.2")', "import ttest").timeit()
def test_part_perf(self):
print
print 'part sad:', timeit.Timer('ttest.is_float_partition("12.2x")', "import ttest").timeit()
print 'part happy:', timeit.Timer('ttest.is_float_partition("12.2")', "import ttest").timeit()
unittest.main()
На моей машине вывод выглядит следующим образом:
fn sad: 0.220988988876
fn happy: 0.212214946747
.
part sad: 1.2219619751
part happy: 0.754667043686
.
re sad: 1.50515985489
re happy: 1.01107215881
.
try sad: 2.40243887901
try happy: 0.425730228424
.
----------------------------------------------------------------------
Ran 4 tests in 7.761s
OK
Как вы можете видеть, регулярное выражение на самом деле не так плохо, как казалось изначально, и если вам действительно нужна скорость, то fastnumbers
метод вполне хорош.