Как я могу проверить, представляет ли строка значение int, без использования try / except?
Есть ли какой-либо способ определить, представляет ли строка целое число (например, '3'
, '-17'
но не '3.14'
или 'asfasfas'
) без использования механизма try / except?
is_int('3.14') == False
is_int('-7') == True
Переведено автоматически
Ответ 1
с целыми положительными числами вы могли бы использовать .isdigit
:
>>> '16'.isdigit()
True
однако это не работает с отрицательными целыми числами. предположим, вы могли бы попробовать следующее:
>>> s = '-17'
>>> s.startswith('-') and s[1:].isdigit()
True
это не будет работать с '16.0'
форматом, который в этом смысле похож на int
приведение.
Редактировать:
def check_int(s):
if s[0] in ('-', '+'):
return s[1:].isdigit()
return s.isdigit()
Ответ 2
Если вас действительно просто раздражает повсеместное использование try/except
s, пожалуйста, просто напишите вспомогательную функцию:
def represents_int(s):
try:
int(s)
except ValueError:
return False
else:
return True
>>> print(represents_int("+123"))
True
>>> print(represents_int("10.0"))
False
Потребуется НАМНОГО больше кода, чтобы точно охватить все строки, которые Python считает целыми. Я говорю, что в этом случае просто используйте pythonic.
Ответ 3
Вы знаете, я обнаружил (и тестировал это снова и снова), что try / except по какой-то причине работает не так хорошо. Я часто пробую несколько способов выполнения действий, и я не думаю, что когда-либо находил метод, который использует try / except для выполнения лучших из протестированных, на самом деле мне кажется, что эти методы обычно оказываются близкими к худшим, если не самыми худшими. Не в каждом случае, но во многих случаях. Я знаю, что многие люди говорят, что это "питонический" способ, но это одна из областей, в которой я с ними расходлюсь. Для меня это не очень производительно и не очень элегантно, поэтому я обычно использую его только для отслеживания ошибок и составления отчетов.
Я собирался пожаловаться, что PHP, perl, ruby, C и даже долбаная оболочка имеют простые функции для проверки строки на целочисленность, но должная осмотрительность при проверке этих предположений сбила меня с толку! По-видимому, этот недостаток является распространенной болезнью.
Вот быстрая и грязная правка поста Бруно:
import sys, time, re
g_intRegex = re.compile(r"^([+-]?[1-9]\d*|0)$")
testvals = [
# integers
0, 1, -1, 1.0, -1.0,
'0', '0.','0.0', '1', '-1', '+1', '1.0', '-1.0', '+1.0', '06',
# non-integers
'abc 123',
1.1, -1.1, '1.1', '-1.1', '+1.1',
'1.1.1', '1.1.0', '1.0.1', '1.0.0',
'1.0.', '1..0', '1..',
'0.0.', '0..0', '0..',
'one', object(), (1,2,3), [1,2,3], {'one':'two'},
# with spaces
' 0 ', ' 0.', ' .0','.01 '
]
def isInt_try(v):
try: i = int(v)
except: return False
return True
def isInt_str(v):
v = str(v).strip()
return v=='0' or (v if v.find('..') > -1 else v.lstrip('-+').rstrip('0').rstrip('.')).isdigit()
def isInt_re(v):
import re
if not hasattr(isInt_re, 'intRegex'):
isInt_re.intRegex = re.compile(r"^([+-]?[1-9]\d*|0)$")
return isInt_re.intRegex.match(str(v).strip()) is not None
def isInt_re2(v):
return g_intRegex.match(str(v).strip()) is not None
def check_int(s):
s = str(s)
if s[0] in ('-', '+'):
return s[1:].isdigit()
return s.isdigit()
def timeFunc(func, times):
t1 = time.time()
for n in range(times):
for v in testvals:
r = func(v)
t2 = time.time()
return t2 - t1
def testFuncs(funcs):
for func in funcs:
sys.stdout.write( "\t%s\t|" % func.__name__)
print()
for v in testvals:
if type(v) == type(''):
sys.stdout.write("'%s'" % v)
else:
sys.stdout.write("%s" % str(v))
for func in funcs:
sys.stdout.write( "\t\t%s\t|" % func(v))
sys.stdout.write("\r\n")
if __name__ == '__main__':
print()
print("tests..")
testFuncs((isInt_try, isInt_str, isInt_re, isInt_re2, check_int))
print()
print("timings..")
print("isInt_try: %6.4f" % timeFunc(isInt_try, 10000))
print("isInt_str: %6.4f" % timeFunc(isInt_str, 10000))
print("isInt_re: %6.4f" % timeFunc(isInt_re, 10000))
print("isInt_re2: %6.4f" % timeFunc(isInt_re2, 10000))
print("check_int: %6.4f" % timeFunc(check_int, 10000))
Вот результаты сравнения производительности:
timings..
isInt_try: 0.6426
isInt_str: 0.7382
isInt_re: 1.1156
isInt_re2: 0.5344
check_int: 0.3452
Метод C мог бы просканировать его один раз и быть выполнен. Я думаю, что метод C, который сканирует строку один раз, был бы правильным решением.
Редактировать:
Я обновил приведенный выше код для работы в Python 3.5 и включил функцию check_int из ответа, получившего наибольшее количество голосов на данный момент, и использовал текущее самое популярное регулярное выражение, которое я могу найти для тестирования на целочисленность. Это регулярное выражение отклоняет строки типа 'abc 123'. Я добавил 'abc 123' в качестве тестового значения.
На данный момент мне очень интересно отметить, что ни одна из протестированных функций, включая метод try, популярную функцию check_int и самое популярное регулярное выражение для тестирования на целочисленность, не возвращает правильные ответы для всех тестовых значений (ну, в зависимости от того, какие ответы вы считаете правильными; смотрите Результаты теста ниже).
Встроенная функция int() автоматически усекает дробную часть числа с плавающей запятой и возвращает целую часть перед десятичной, если только число с плавающей запятой не преобразовано сначала в строку.
Функция check_int() возвращает false для значений типа 0.0 и 1.0 (которые технически являются целыми числами) и возвращает true для значений типа '06'.
Вот текущие результаты тестирования (Python 3.5):
isInt_try | isInt_str | isInt_re | isInt_re2 | check_int |
0 True | True | True | True | True |
1 True | True | True | True | True |
-1 True | True | True | True | True |
1.0 True | True | False | False | False |
-1.0 True | True | False | False | False |
'0' True | True | True | True | True |
'0.' False | True | False | False | False |
'0.0' False | True | False | False | False |
'1' True | True | True | True | True |
'-1' True | True | True | True | True |
'+1' True | True | True | True | True |
'1.0' False | True | False | False | False |
'-1.0' False | True | False | False | False |
'+1.0' False | True | False | False | False |
'06' True | True | False | False | True |
'abc 123' False | False | False | False | False |
1.1 True | False | False | False | False |
-1.1 True | False | False | False | False |
'1.1' False | False | False | False | False |
'-1.1' False | False | False | False | False |
'+1.1' False | False | False | False | False |
'1.1.1' False | False | False | False | False |
'1.1.0' False | False | False | False | False |
'1.0.1' False | False | False | False | False |
'1.0.0' False | False | False | False | False |
'1.0.' False | False | False | False | False |
'1..0' False | False | False | False | False |
'1..' False | False | False | False | False |
'0.0.' False | False | False | False | False |
'0..0' False | False | False | False | False |
'0..' False | False | False | False | False |
'one' False | False | False | False | False |
<obj..> False | False | False | False | False |
(1, 2, 3) False | False | False | False | False |
[1, 2, 3] False | False | False | False | False |
{'one': 'two'} False | False | False | False | False |
' 0 ' True | True | True | True | False |
' 0.' False | True | False | False | False |
' .0' False | False | False | False | False |
'.01 ' False | False | False | False | False |
Только что я попробовал добавить эту функцию:
def isInt_float(s):
try:
return float(str(s)).is_integer()
except:
return False
Он работает почти так же хорошо, как check_int (0.3486), и возвращает true для таких значений, как 1.0 и 0.0 , и + 1.0 и 0. и .0 и так далее. Но он также возвращает true для '06', так что. Выбирай яд, я думаю.
Ответ 4
str.isdigit()
должно получиться.
Примеры:
str.isdigit("23") ## True
str.isdigit("abc") ## False
str.isdigit("23.4") ## False
Редактировать:
Как указал @BuzzMoschetti, этот способ завершится неудачей для минус-числа (например, "-23"). В случае, если ваше input_num может быть меньше 0, используйте re.sub(regex_search,regex_replace,contents) перед применением str.isdigit(). Например:
import re
input_num = "-23"
input_num = re.sub("^-", "", input_num) ## "^" indicates to remove the first "-" only
str.isdigit(input_num) ## True