有没有办法判断字符串是否代表整数(例如'3'
,'-17'
但不是'3.14'
或'asfasfas'
)不使用try / except机制?
is_int('3.14') = False
is_int('-7') = True
答案 0 :(得分:605)
使用正整数,您可以使用.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()
答案 1 :(得分:325)
如果你真的只是厌倦了使用try/except
的所有地方,请写一个帮助函数:
def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
return False
>>> print RepresentsInt("+123")
True
>>> print RepresentsInt("10.0")
False
这将是更多的代码来完全覆盖Python认为整数的所有字符串。我说这个就是pythonic。
答案 2 :(得分:76)
你知道,我已经找到了(并且我已经反复测试过),无论出于什么原因,尝试/除了不能很好地执行。我经常尝试几种做事方式,我不认为我曾经找到过使用try / except来执行最佳测试的方法,事实上在我看来这些方法通常都接近于最坏的,如果不是最坏的。并非在所有情况下,但在许多情况下。我知道很多人都说这是“Pythonic”的方式,但这是我与他们分道扬with的一个方面。对我而言,它既不是非常高效也不是非常优雅,因此,我倾向于仅将其用于错误捕获和报告。
我会抱怨PHP,perl,ruby,C,甚至是怪异的shell都有简单的函数来测试整数引擎的字符串,但是在验证这些假设的尽职调查让我感到沮丧!显然这种缺乏是一种常见的疾病。
这是Bruno的帖子快速而又脏的编辑:
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()函数以静默方式截断浮点数的小数部分,并返回小数之前的整数部分,除非浮点数首先转换为字符串。
对于像0.0和1.0这样的值(技术上是整数),check_int()函数返回false,对于像'06'这样的值,返回true。
以下是当前(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)一样,并且对于1.0和0.0以及+1.0和0以及.0之类的值返回true,依此类推。但它也会在'06'中返回true,所以。我想,选择你的毒药。
答案 3 :(得分:23)
使用正则表达式:
import re
def RepresentsInt(s):
return re.match(r"[-+]?\d+$", s) is not None
如果您还必须接受小数部分:
def RepresentsInt(s):
return re.match(r"[-+]?\d+(\.0*)?$", s) is not None
如果您经常这样做,为了提高性能,请使用re.compile()
仅编译正则表达式一次。
答案 4 :(得分:16)
正确的RegEx解决方案将结合Greg Hewgill和Nowell的想法,但不使用全局变量。您可以通过将属性附加到方法来完成此操作。另外,我知道将导入放在方法中是不受欢迎的,但我想要的是像http://peak.telecommunity.com/DevCenter/Importing#lazy-imports
这样的“懒惰模块”效果编辑:到目前为止,我最喜欢的技术是使用String对象的专有方法。
#!/usr/bin/env python
# Uses exclusively methods of the String object
def isInteger(i):
i = str(i)
return i=='0' or (i if i.find('..') > -1 else i.lstrip('-+').rstrip('0').rstrip('.')).isdigit()
# Uses re module for regex
def isIntegre(i):
import re
if not hasattr(isIntegre, '_re'):
print("I compile only once. Remove this line when you are confident in that.")
isIntegre._re = re.compile(r"[-+]?\d+(\.0*)?$")
return isIntegre._re.match(str(i)) is not None
# When executed directly run Unit Tests
if __name__ == '__main__':
for obj in [
# integers
0, 1, -1, 1.0, -1.0,
'0', '0.','0.0', '1', '-1', '+1', '1.0', '-1.0', '+1.0',
# non-integers
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'}
]:
# Notice the integre uses 're' (intended to be humorous)
integer = ('an integer' if isInteger(obj) else 'NOT an integer')
integre = ('an integre' if isIntegre(obj) else 'NOT an integre')
# Make strings look like strings in the output
if isinstance(obj, str):
obj = ("'%s'" % (obj,))
print("%30s is %14s is %14s" % (obj, integer, integre))
对于不太冒险的班级成员,这是输出:
I compile only once. Remove this line when you are confident in that.
0 is an integer is an integre
1 is an integer is an integre
-1 is an integer is an integre
1.0 is an integer is an integre
-1.0 is an integer is an integre
'0' is an integer is an integre
'0.' is an integer is an integre
'0.0' is an integer is an integre
'1' is an integer is an integre
'-1' is an integer is an integre
'+1' is an integer is an integre
'1.0' is an integer is an integre
'-1.0' is an integer is an integre
'+1.0' is an integer is an integre
1.1 is NOT an integer is NOT an integre
-1.1 is NOT an integer is NOT an integre
'1.1' is NOT an integer is NOT an integre
'-1.1' is NOT an integer is NOT an integre
'+1.1' is NOT an integer is NOT an integre
'1.1.1' is NOT an integer is NOT an integre
'1.1.0' is NOT an integer is NOT an integre
'1.0.1' is NOT an integer is NOT an integre
'1.0.0' is NOT an integer is NOT an integre
'1.0.' is NOT an integer is NOT an integre
'1..0' is NOT an integer is NOT an integre
'1..' is NOT an integer is NOT an integre
'0.0.' is NOT an integer is NOT an integre
'0..0' is NOT an integer is NOT an integre
'0..' is NOT an integer is NOT an integre
'one' is NOT an integer is NOT an integre
<object object at 0x103b7d0a0> is NOT an integer is NOT an integre
(1, 2, 3) is NOT an integer is NOT an integre
[1, 2, 3] is NOT an integer is NOT an integre
{'one': 'two'} is NOT an integer is NOT an integre
答案 5 :(得分:6)
- shape (class: SpatialPolygonsDataFrame)
... @data: 'data.frame'
.. ...$STATE
...
- data (class: matrix):
>A B C D
>11 2 3 2
>7 10 0 1
>4 5 3 5
>0 3 13 5
应该可以解决问题。
示例:
str.isdigit()
答案 6 :(得分:4)
Greg Hewgill的方法缺少一些组件:前导“^”只匹配字符串的开头,并预先编译re。但是这种方法可以让你避免尝试:exept:
import re
INT_RE = re.compile(r"^[-]?\d+$")
def RepresentsInt(s):
return INT_RE.match(str(s)) is not None
我很感兴趣为什么你要避免尝试:除了?
答案 7 :(得分:4)
我使用的最简单的方法
def is_int(item: str) -> bool:
return item.lstrip('-+').isdigit()
答案 8 :(得分:3)
>>> "+7".lstrip("-+").isdigit()
True
>>> "-7".lstrip("-+").isdigit()
True
>>> "7".lstrip("-+").isdigit()
True
>>> "13.4".lstrip("-+").isdigit()
False
所以你的功能是:
def is_int(val):
return val[1].isdigit() and val.lstrip("-+").isdigit()
答案 9 :(得分:2)
我认为
s.startswith('-') and s[1:].isdigit()
最好重写为:
s.replace('-', '').isdigit()
因为s [1:]也会创建一个新字符串
但更好的解决方案是
s.lstrip('+-').isdigit()
答案 10 :(得分:2)
我真的很喜欢Shavais&#39;发布,但我又添加了一个测试用例(&amp;内置的isdigit()函数):
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
$guard = array_get($exception->guards(), 0);
switch($guard) {
case "admin":
$login = "admin-login";
break;
default:
$login = "login";
break;
}
}
return redirect()->guest(route($login));
}
它显着地一致地击败了剩下的时间:
def isInt_loop(v):
v = str(v).strip()
# swapping '0123456789' for '9876543210' makes nominal difference (might have because '1' is toward the beginning of the string)
numbers = '0123456789'
for i in v:
if i not in numbers:
return False
return True
def isInt_Digit(v):
v = str(v).strip()
return v.isdigit()
使用普通的2.7 python:
timings..
isInt_try: 0.4628
isInt_str: 0.3556
isInt_re: 0.4889
isInt_re2: 0.2726
isInt_loop: 0.1842
isInt_Digit: 0.1577
我添加的两个测试用例(isInt_loop和isInt_digit)都传递完全相同的测试用例(它们都只接受无符号整数),但我认为人们可能更聪明地修改字符串实现(isInt_loop)而不是内置了isdigit()函数,所以我把它包括在内,即使执行时间略有不同。 (并且这两种方法都在很多方面击败了其他所有方法,但不要处理额外的东西:&#34; ./+/-")
此外,我确实发现有趣的是,正则表达式(isInt_re2方法)在Shavais在2012年(目前为2018年)执行的相同测试中击败了字符串比较。也许正则表达式库得到了改进?
答案 11 :(得分:1)
这是一个解析而不会引发错误的函数。它处理明显的情况下失败时返回None
(默认情况下在CPython上处理最多2000' - / +'符号!):
#!/usr/bin/env python
def get_int(number):
splits = number.split('.')
if len(splits) > 2:
# too many splits
return None
if len(splits) == 2 and splits[1]:
# handle decimal part recursively :-)
if get_int(splits[1]) != 0:
return None
int_part = splits[0].lstrip("+")
if int_part.startswith('-'):
# handle minus sign recursively :-)
return get_int(int_part[1:]) * -1
# successful 'and' returns last truth-y value (cast is always valid)
return int_part.isdigit() and int(int_part)
一些测试:
tests = ["0", "0.0", "0.1", "1", "1.1", "1.0", "-1", "-1.1", "-1.0", "-0", "--0", "---3", '.3', '--3.', "+13", "+-1.00", "--+123", "-0.000"]
for t in tests:
print "get_int(%s) = %s" % (t, get_int(str(t)))
结果:
get_int(0) = 0
get_int(0.0) = 0
get_int(0.1) = None
get_int(1) = 1
get_int(1.1) = None
get_int(1.0) = 1
get_int(-1) = -1
get_int(-1.1) = None
get_int(-1.0) = -1
get_int(-0) = 0
get_int(--0) = 0
get_int(---3) = -3
get_int(.3) = None
get_int(--3.) = 3
get_int(+13) = 13
get_int(+-1.00) = -1
get_int(--+123) = 123
get_int(-0.000) = 0
根据您的需要,您可以使用:
def int_predicate(number):
return get_int(number) is not None
答案 12 :(得分:1)
前提:
int()
的行为是我们的标准(有时很奇怪:“-00”是它的正确输入)简答:
使用以下代码。它简单、正确(虽然此线程中的许多变体并非如此)并且try/except
和{{}几乎两倍胜过 1}} 个变体。
regex
TL;DR 答案:
我测试了 3 个主要变体 (1) try/except,(2) re.match() 和 (3) 字符串操作(见上文)。第三个变体比 def is_int_str(string):
return (
string.startswith(('-', '+')) and string[1:].isdigit()
) or string.isdigit()
和 try/except
快大约两倍。顺便说一句:正则表达式变体是最慢的!请参阅下面的测试脚本。
re.match()
输出是:
import re
import time
def test(func, test_suite):
for test_case in test_suite:
actual_result = func(*test_case[0])
expected_result = test_case[1]
assert (
actual_result == expected_result
), f'Expected: {expected_result} but actual: {actual_result}'
def perf(func, test_suite):
start = time.time()
for _ in range(0, 1_000_000):
test(func, test_suite)
return time.time() - start
def is_int_str_1(string):
try:
int(string)
return True
except ValueError:
return False
def is_int_str_2(string):
return re.match(r'^[\-+]?\d+$', string) is not None
def is_int_str_3(string):
return (
string.startswith(('-', '+')) and string[1:].isdigit()
) or string.isdigit()
# Behavior of built-in int() function is a standard for the following tests
test_suite = [
[['1'], True], # func('1') -> True
[['-1'], True],
[['+1'], True],
[['--1'], False],
[['++1'], False],
[['001'], True], # because int() can read it
[['-00'], True], # because of quite strange behavior of int()
[['-'], False],
[['abracadabra'], False],
[['57938759283475928347592347598357098458405834957984755200000000'], True],
]
time_span_1 = perf(is_int_str_1, test_suite)
time_span_2 = perf(is_int_str_2, test_suite)
time_span_3 = perf(is_int_str_3, test_suite)
print(f'{is_int_str_1.__name__}: {time_span_1} seconds')
print(f'{is_int_str_2.__name__}: {time_span_2} seconds')
print(f'{is_int_str_3.__name__}: {time_span_3} seconds')
答案 13 :(得分:1)
我用这个:
val workManager = WorkManager.getInstance(myContext)
// Create all your work
val workA, workB, workC, workZ, workD, workE, workF
// Then build chain1
val chain1 = workManager.beginWith(workA)
.then(workB)
.then(workC)
// Now link in both Z and D
chain1.then(workZ, workD)
.enqueue()
// There's nothing after Z, so there's no explict work
// you need to do for chain2
// Then build off of D to finish chain3
workManager.beginWith(workD)
.then(workE)
.then(workF)
.enqueue()
它不包含负数,因此您可以使用:
all([xi in '1234567890' for xi in x])
如果不确定输入是否为字符串,也可以将x传递给str():
all([xi in '1234567890-' for xi in x])
至少有两种(边缘?)情况会崩溃:
all([xi in '1234567890-' for xi in str(x)])
,则会得到type(1E3)
所以它不适用于所有的可能输入,但是如果您可以排除这些可能性,则可以单行检查,如果x不是整数,则返回<class 'float'>
。我不知道它是否是pythonic,但这只是一行,而且相对清楚代码的作用。
答案 14 :(得分:1)
在我看来,这可能是接近它的最简单和pythonic方式。我没有看到这个解决方案,它与正则表达式基本相同,但没有正则表达式。
def is_int(test):
import string
return not (set(test) - set(string.digits))
答案 15 :(得分:0)
我想这个问题与速度有关,因为try / except有时间限制:
首先,我创建了一个包含200个字符串,100个失败字符串和100个数字字符串的列表。
from random import shuffle
numbers = [u'+1'] * 100
nonumbers = [u'1abc'] * 100
testlist = numbers + nonumbers
shuffle(testlist)
testlist = np.array(testlist)
np.core.defchararray.isnumeric也可以与unicode字符串np.core.defchararray.isnumeric(u'+12')
一起使用,但是它会返回和数组。因此,如果您必须进行数千次转换并且缺少数据或非数字数据,这是一个很好的解决方案。
import numpy as np
%timeit np.core.defchararray.isnumeric(testlist)
10000 loops, best of 3: 27.9 µs per loop # 200 numbers per loop
def check_num(s):
try:
int(s)
return True
except:
return False
def check_list(l):
return [check_num(e) for e in l]
%timeit check_list(testlist)
1000 loops, best of 3: 217 µs per loop # 200 numbers per loop
似乎numpy解决方案要快得多。
答案 16 :(得分:0)
如果您只想接受低位数字,请执行以下测试:
Python 3.7+:(u.isdecimal() and u.isascii())
Python <= 3.6:(u.isdecimal() and u == str(int(u)))
其他答案建议使用.isdigit()
或.isdecimal()
,但这些both include some upper-unicode characters如'٢'
(u'\u0662'
):
u = u'\u0662' # '٢'
u.isdigit() # True
u.isdecimal() # True
u.isascii() # False (Python 3.7+ only)
u == str(int(u)) # False
答案 17 :(得分:0)
我建议以下内容:
import ast
def is_int(s):
return isinstance(ast.literal_eval(s), int)
来自docs:
安全地评估表达式节点或包含Python文字或容器显示的字符串。提供的字符串或节点只能由以下Python文字结构组成:字符串,字节,数字,元组,列表,字典,集合,布尔值和无。
我应该注意,当对任何不构成Python文字的内容进行调用时,这将引发ValueError
异常。由于问题要求的解决方案没有try / except,因此我为此准备了Kobayashi-Maru型解决方案:
from ast import literal_eval
from contextlib import suppress
def is_int(s):
with suppress(ValueError):
return isinstance(literal_eval(s), int)
return False
¯\ _(ツ)_ /¯
答案 18 :(得分:0)
我有一种可能根本不使用int,除非字符串不代表数字,否则不应引发异常
float(number)==float(number)//1
它适用于浮动接受的任何类型的字符串,正面,负面,工程符号......
答案 19 :(得分:0)
可以使用下面的方法来检查。
def check_if_string_is_int(string1):
for character in string1:
if not character.isdigit():
return "Not a number"
else:
return "Is a number"
答案 20 :(得分:-1)
def is_int_or_float(x):
try:
if int(float(x)):
if float(x).is_integer(): return 'int'
else: return 'float'
except ValueError: return False
for i in ['*', '-1', '01', '1.23', '+0011.002', ]:
print(i, is_int_or_float(i))
# * False
# -1 int
# 01 int
# 1.23 float
# +0011.002 float
答案 21 :(得分:-5)
呃..试试这个:
def int_check(a):
if int(a) == a:
return True
else:
return False
如果您没有输入不是数字的字符串,则此方法有效。
而且(我忘了把数字检查部分。),有一个函数检查字符串是否是数字。它是str.isdigit()。这是一个例子:
a = 2
a.isdigit()
如果你调用a.isdigit(),它将返回True。