Проверка, может ли строка быть преобразована в 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 и посмотреть, удастся ли ему выполнить, как описано в этом вопросе.
У кого-нибудь есть другие идеи? Мнения относительно относительных достоинств раздела и попыток/подходов?
Ответы
Ответ 1
Я бы просто использовал..
try:
float(element)
except ValueError:
print "Not a float"
.. он прост, и он работает
Другим вариантом будет регулярное выражение:
import re
if re.match("^\d+?\.\d+?$", element) is None:
print "Not float"
Ответ 2
Метод Python для проверки float:
def isfloat(value):
try:
float(value)
return True
except ValueError:
return False
Не бойся гоблинов, скрывающихся в поплавковой лодке! ПРОВЕРЬТЕ ТЕСТИРОВАНИЕ УСТРОЙСТВА!
Что есть, и не плавающий может вас удивить:
Command to parse Is it a float? Comment
-------------------------------------- --------------- ------------
print(isfloat("")) False
print(isfloat("1234567")) True
print(isfloat("NaN")) True nan is also float
print(isfloat("NaNananana BATMAN")) False
print(isfloat("123.456")) True
print(isfloat("123.E4")) True
print(isfloat(".1")) True
print(isfloat("1,234")) False
print(isfloat("NULL")) False case insensitive
print(isfloat(",1")) False
print(isfloat("123.EE4")) False
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("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
Ответ 3
Если вы заботитесь о производительности (и я не предлагаю вам этого делать), подход на основе try-the-the clear победит (по сравнению с вашим подходом на основе разделов или подходом regexp), если вы не ожидаете много недопустимых строк, и в этом случае он потенциально медленнее (предположительно из-за стоимости обработки исключений).
Опять же, я не предлагаю вам заботиться о производительности, просто давая вам данные, если вы делаете это 10 миллиардов раз в секунду или что-то в этом роде. Кроме того, код на основе раздела не обрабатывает хотя бы одну допустимую строку.
$ ./floatstr.py
F..
partition sad: 3.1102449894
partition happy: 2.09208488464
..
re sad: 7.76906108856
re happy: 7.09421992302
..
try sad: 12.1525540352
try happy: 1.44165301323
.
======================================================================
FAIL: test_partition (__main__.ConvertTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "./floatstr.py", line 48, in test_partition
self.failUnless(is_float_partition("20e2"))
AssertionError
----------------------------------------------------------------------
Ran 8 tests in 33.670s
FAILED (failures=1)
Здесь код (Python 2.6, regexp, взятый из John Gietzen answer):
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)?$")
def is_float_re(str):
return re.match(_float_regexp, str)
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 pa\
rtition[2].isdigit()) or (partition[0].isdigit() and partition[1]=='.' and partition[2]==''):
return True
if __name__ == '__main__':
import unittest
import timeit
class ConvertTests(unittest.TestCase):
def test_re(self):
self.failUnless(is_float_re("20e2"))
def test_try(self):
self.failUnless(is_float_try("20e2"))
def test_re_perf(self):
print
print 're sad:', timeit.Timer('floatstr.is_float_re("12.2x")', "import floatstr").timeit()
print 're happy:', timeit.Timer('floatstr.is_float_re("12.2")', "import floatstr").timeit()
def test_try_perf(self):
print
print 'try sad:', timeit.Timer('floatstr.is_float_try("12.2x")', "import floatstr").timeit()
print 'try happy:', timeit.Timer('floatstr.is_float_try("12.2")', "import floatstr").timeit()
def test_partition_perf(self):
print
print 'partition sad:', timeit.Timer('floatstr.is_float_partition("12.2x")', "import floatstr").timeit()
print 'partition happy:', timeit.Timer('floatstr.is_float_partition("12.2")', "import floatstr").timeit()
def test_partition(self):
self.failUnless(is_float_partition("20e2"))
def test_partition2(self):
self.failUnless(is_float_partition(".2"))
def test_partition3(self):
self.failIf(is_float_partition("1234x.2"))
unittest.main()
Ответ 4
TL; DR:
- Если ваш ввод - это в основном строки, которые можно преобразовать в float, метод
try: except:
является лучшим нативным методом Python.
- Если ваш ввод - это в основном строки, которые нельзя преобразовать в поплавки, регулярные выражения или метод разделения будут лучше.
- Если вы 1) не уверены в своем вводе или нуждаетесь в большей скорости и 2) не возражаете и можете установить стороннее C-расширение, fastnumbers работает очень хорошо.
Существует другой метод, доступный через сторонний модуль под названием fastnumbers (раскрытие, я являюсь автором); он предоставляет функцию под названием isfloat. Я принял пример unittest, описанный Яковом Габриэльсоном в этом ответе, но добавил метод fastnumbers.isfloat
. Следует также отметить, что пример Джейкоба не оправдывал вариант регулярного выражения, потому что большую часть времени в этом примере тратили на глобальные поиски из-за оператора точек... Я изменил эту функцию, чтобы дать более справедливое сравнение с 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
неплох.
Ответ 5
Это регулярное выражение будет проверять научные числа с плавающей запятой:
^[-+]?(?:\b[0-9]+(?:\.[0-9]*)?|\.[0-9]+\b)(?:[eE][-+]?[0-9]+\b)?$
Однако я считаю, что лучше всего использовать синтаксический анализатор в попытке.
Ответ 6
'1.43'.replace('.','',1).isdigit()
который вернет true
, только если есть один или нет. в строке цифр.
'1.4.3'.replace('.','',1).isdigit()
вернет false
'1.ww'.replace('.','',1).isdigit()
вернет false
Ответ 7
Если вам не нужно беспокоиться о научных или других выражениях чисел и работать со строками, которые могут быть числами с периодом или без него:
Функция
def is_float(s):
result = False
if s.count(".") == 1:
if s.replace(".", "").isdigit():
result = True
return result
Лямбда версия
is_float = lambda x: x.replace('.','',1).isdigit() and "." in x
Пример
if is_float(some_string):
some_string = float(some_string)
elif some_string.isdigit():
some_string = int(some_string)
else:
print "Does not convert to int or float."
Таким образом, вы не случайно конвертируете то, что должно быть int, в float.
Ответ 8
Я использовал уже упомянутую функцию, но вскоре я заметил, что строки как "Нан", "Инф" и ее вариация рассматриваются как число. Поэтому я предлагаю вам улучшенную версию функции, которая вернет 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
Ответ 9
str (strval).isdigit() кажется простым. Обрабатывает значения, хранящиеся в виде строки или int или float