Como posso verificar se uma string representa um int, sem usar try / except?
467
Existe alguma maneira de saber se uma string representa um número inteiro (por exemplo '3', '-17'mas não '3.14'ou 'asfasfas') sem usar um mecanismo try / except?
Por que ambos tentando fazer isso "da maneira mais difícil?" O que há de errado com try / except?
S.Lott
5
Sim, o que há de errado com try / except? Melhor pedir perdão do que permissão.
Mk12 14/09/09
53
Gostaria de perguntar por que essa coisa simples requer tentativa / exceto? O sistema de exceção é um animal complexo, mas esse é um problema simples.
Aivar 23/09
13
@Aivar para de espalhar FUD. Um único bloco try / except nem se aproxima de "complexo".
Triptych
47
Não é realmente FUD, no entanto. Você escreveria efetivamente 4 linhas de código, esperando que algo explodisse, capturando essa exceção e fazendo o padrão, em vez de usar um liner.
andersonvom
Respostas:
398
Se você está realmente irritado com o uso de try/excepts em todo o lugar, basta escrever uma função auxiliar:
Portanto, é pitônico resolver um problema simples com mecanismos complexos? Existe um algoritmo para detectar a função interna "int" escrita por int - não vejo por que isso não é exposto como uma função booleana.
Aivar 23/09
79
@Aivar: Esta função de 5 linhas não é um mecanismo complexo.
Eu acho que é "pythonic" no sentido de que se o Python acha que a string é um int, o mesmo acontece com o seu programa. Se o Python mudar, seu programa também mudará, e sem alterar uma única linha de código. Há algum valor nisso. Pode ser a coisa certa a fazer, dependendo das circunstâncias.
Shavais
57
Não sei por que essa é a resposta aceita ou tem tantos votos positivos, pois é exatamente o oposto do que o OP está pedindo.
FearlessFuture
756
com números inteiros positivos você pode usar .isdigit:
>>>'16'.isdigit()True
embora não funcione com números inteiros negativos. suponha que você possa tentar o seguinte:
>>> s ='-17'>>> s.startswith('-')and s[1:].isdigit()True
não funcionará com o '16.0'formato, que é semelhante ao intvazamento nesse sentido.
isso não lida com "+17" sem um caso especial adicional.
11139 Bryan Oakley
1
Você tem que testar para ambos os casos: lambda s: s.isdigit () ou (s.startswith ( '-') e s [1:]. Isdigit ())
Rob
4
@ Roberto: é claro que você deveria! e tenho certeza que você é capaz de fazê-lo!
SilentGhost
22
nota: u'²'.isdigit()é verdade, mas int(u'²')gera ValueError. Use em u.isdecimal()vez disso. str.isdigit()é dependente da localidade no Python 2. #
jfs
4
check_int('')irá gerar uma exceção em vez de voltarFalse
wordbug
97
Você sabe, eu descobri (e testei isso várias vezes) que tentar / exceto não funciona tão bem, por qualquer motivo. Frequentemente, tento várias maneiras de fazer as coisas e acho que nunca encontrei um método que use try / exceto para executar o melhor dos testados; na verdade, parece-me que esses métodos geralmente se aproximam do pior, se não o pior. Não em todos os casos, mas em muitos casos. Eu sei que muitas pessoas dizem que é o caminho "Pythonic", mas essa é uma área em que me separo deles. Para mim, não é muito eficiente nem muito elegante; portanto, costumo usá-lo apenas para capturar e reportar erros.
Eu ia entender que PHP, perl, ruby, C e até mesmo o maldito shell têm funções simples para testar uma string para um número inteiro, mas a devida diligência em verificar essas suposições me levou a sério! Aparentemente, essa falta é uma doença comum.
Aqui está uma edição rápida e suja da postagem de Bruno:
import sys, time, re
g_intRegex = re.compile(r"^([+-]?[1-9]\d*|0)$")
testvals =[# integers0,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:returnFalsereturnTruedef isInt_str(v):
v = str(v).strip()return v=='0'or(v if v.find('..')>-1else v.lstrip('-+').rstrip('0').rstrip('.')).isdigit()def isInt_re(v):import re
ifnot hasattr(isInt_re,'intRegex'):
isInt_re.intRegex = re.compile(r"^([+-]?[1-9]\d*|0)$")return isInt_re.intRegex.match(str(v).strip())isnotNonedef isInt_re2(v):return g_intRegex.match(str(v).strip())isnotNonedef 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))
Aqui estão os resultados da comparação de desempenho:
O método AC pode digitalizá-lo uma vez e concluir. O método AC que varre a string uma vez seria a coisa certa a fazer, eu acho.
EDITAR:
Atualizei o código acima para trabalhar no Python 3.5 e incluir a função check_int da resposta mais votada no momento e para usar o regex mais popular atual que posso encontrar para testar o número inteiro. Esse regex rejeita seqüências de caracteres como 'abc 123'. Eu adicionei 'abc 123' como um valor de teste.
É muito interessante para mim observar, neste ponto, que NENHUMA das funções testadas, incluindo o método try, a popular função check_int e o regex mais popular para testar a integração de números inteiros, retornam as respostas corretas para todos os valores de teste (bem, dependendo das respostas corretas, consulte os resultados do teste abaixo).
A função interna int () silenciosamente trunca a parte fracionária de um número de ponto flutuante e retorna a parte inteira antes do decimal, a menos que o número do ponto flutuante seja primeiro convertido em uma seqüência de caracteres.
A função check_int () retorna false para valores como 0.0 e 1.0 (que tecnicamente são números inteiros) e retorna true para valores como '06'.
Aqui estão os resultados dos testes atuais (Python 3.5):
Ele executa quase tão bem quanto check_int (0.3486) e retorna true para valores como 1.0 e 0.0 e +1.0 e 0. e .0 e assim por diante. Mas também retorna verdadeiro para '06', então. Escolha seu veneno, eu acho.
Talvez parte disso venha do fato de um número inteiro ser um pouco arbitrário. Um sistema de programação não pode se dar ao luxo de assumir que sempre será uma representação decimal. 0x4df, é um número inteiro válido em alguns lugares e 0891 não está em outros. Temo pensar no que possa surgir, dado o unicode nesses tipos de verificação.
PlexQ
3
+1 para o tempo. Concordo que todo esse negócio de exceção não seja realmente elegante para uma pergunta tão simples. Você esperaria uma compilação no método auxiliar para um problema tão comum ...
RickyA
9
Eu sei que esse segmento está basicamente inativo, mas +1 por considerar o tempo de execução. O comprimento da linha nem sempre é indicativo da complexidade subjacente; e, com certeza, uma tentativa / exceção pode parecer simples (e fácil de ler, o que também é importante), mas é uma operação cara. Eu diria que a hierarquia de preferências deve sempre ser algo como o seguinte: 1. Uma solução explícita de fácil leitura (SilentGhost). 2. Uma solução implícita de fácil leitura (Triptych). 3. Não há três.
Eric Humphrey
1
Obrigado por suas investigações sobre este tópico aparentemente insignificante. Eu vou com o isInt_str (), pythonic ou não. O que me incomoda é que não encontrei nada sobre o significado de v.find ('..'). Isso é algum tipo de sintaxe de busca especial ou um caso de borda de uma sequência numérica?
JackLeEmmerdeur
3
Sim, uma análise um pouco datada, mas ainda muito agradável e relevante. No Python 3.5, tryé mais eficiente: isInt_try: 0.6552 / isInt_str: 0.6396 / isInt_re: 1.0296 / isInt_re2: 0.5168.
EDIT : Como o @BuzzMoschetti apontou, esse caminho falhará no número negativo (por exemplo, "-23" ). Caso seu input_num possa ser menor que 0, use re.sub (regex_search, regex_replace, contents) antes de aplicar str.isdigit () . Por exemplo:
import re
input_num ="-23"
input_num = re.sub("^-","", input_num)## "^" indicates to remove the first "-" only
str.isdigit(input_num)## True
@BuzzMoschetti você está certo. Uma maneira rápida de correção é remover sinal de menos por re.replace (regex_search, regex_replace, conteúdos) antes de aplicar str.isdigit ()
Catbuilts
27
Use uma expressão regular:
import re
defRepresentsInt(s):return re.match(r"[-+]?\d+$", s)isnotNone
+1: revela que isso é terrivelmente complexo e caro quando comparado com a tentativa / exceção.
S.Lott
2
Eu sinto que essa é essencialmente uma versão mais lenta e personalizada da solução 'isumérica' oferecida pelo @SilentGhost.
Greg
@ Greg: Como o @ SilentGhost não cobre os sinais corretamente, esta versão realmente funciona.
S.Lott
1
@ S.Lott: certamente, qualquer pessoa capaz de postar no SO, seria capaz de estender meu exemplo para cobrir sinais.
SilentGhost
2
Como expressões regulares são sobre a coisa mais complexa e obscura existente, acho que a verificação simples acima é substancialmente mais clara, mesmo que eu ache ainda feia, isso é mais feio.
PlexQ
18
A solução RegEx adequada combinaria as idéias de Greg Hewgill e Nowell, mas não usaria uma variável global. Você pode fazer isso anexando um atributo ao método Além disso, eu sei que é desagradável colocar as importações em um método, mas o que eu desejo é um efeito de "módulo lento" como http://peak.telecommunity.com/DevCenter/Importing#lazy-imports
editar: Minha técnica favorita até agora é usar exclusivamente métodos do objeto String.
#!/usr/bin/env python# Uses exclusively methods of the String objectdef isInteger(i):
i = str(i)return i=='0'or(i if i.find('..')>-1else i.lstrip('-+').rstrip('0').rstrip('.')).isdigit()# Uses re module for regexdef isIntegre(i):import re
ifnot 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))isnotNone# When executed directly run Unit Testsif __name__ =='__main__':for obj in[# integers0,1,-1,1.0,-1.0,'0','0.','0.0','1','-1','+1','1.0','-1.0','+1.0',# non-integers1.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 outputif isinstance(obj, str):
obj =("'%s'"%(obj,))print("%30s is %14s is %14s"%(obj, integer, integre))
E para os membros menos aventureiros da classe, aqui está a saída:
I compile only once.Remove this line when you are confident in that.0is an integer is an integre
1is an integer is an integre
-1is an integer is an integre
1.0is an integer is an integre
-1.0is 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.1is NOT an integer is NOT an integre
-1.1is 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
Concordo que minha suíte de testes é um exagero. Eu gosto de provar que meu código funciona quando eu o escrevo. Mas você acha que minha função isInteger é um exagero? Certamente não.
Bruno Brosky
1
Acabei de receber uma votação sem comentários. O que há com as pessoas? Entendo que a geração do milênio agora esteja usando "Likes" como "recibos de leitura". Mas eles agora estão usando votos negativos como "não o método que eu escolhi"? Talvez eles não percebam que isso subtrai 2 pontos da SUA PRÓPRIA reputação para votar uma resposta. SO / SE faz isso para incentivar a votação baixa apenas devido a informações erradas; nesse caso, espero que você deixe um comentário .
A abordagem de Greg Hewgill estava faltando alguns componentes: o "^" principal para corresponder apenas ao início da string e compilando o re antecipadamente. Mas essa abordagem permitirá que você evite uma tentativa: exept:
import re
INT_RE = re.compile(r"^[-]?\d+$")defRepresentsInt(s):return INT_RE.match(str(s))isnotNone
Eu estaria interessado em saber por que você está tentando evitar a tentativa: exceto?
Uma questão de estilo. Eu acho que "try / except" deve ser usado apenas com erros reais, não com o fluxo normal do programa.
14339 Adam Matan
2
@Udi Pasmon: Python usa bastante o try / exceto o fluxo de programa "normal". Por exemplo, todo iterador para com uma exceção levantada.
S.Lott
3
-1: Embora sua dica de compilar o regex esteja correta, você está errado ao criticar Greg em outro aspecto: re.match corresponde ao início da string, portanto o ^ no padrão é realmente redundante. (Isso é diferente quando você usa re.search).
ThomasH
S.Lott - Esse fluxo é considerado razoável em python? Como isso difere de outros idiomas? Talvez valha uma pergunta separada.
14119 Adam Matan
1
O uso intenso de try / except do Python foi abordado aqui no SO. Tente uma pesquisa por '[python] exceto'
S.Lott 12/08/2009
4
Eu tenho que fazer isso o tempo todo e tenho uma aversão leve, mas reconhecidamente irracional, ao uso do padrão try / except. Eu uso isso:
all([xi in'1234567890'for xi in x])
Ele não acomoda números negativos; portanto, você pode retirar um sinal de menos (se houver) e verificar se o resultado inclui dígitos de 0 a 9:
all([xi in'1234567890'for xi in x.replace('-','',1)])
Você também pode passar x para str () se não tiver certeza de que a entrada é uma string:
all([xi in'1234567890'for xi in str(x).replace('-','',1)])
Há pelo menos dois casos (edge?) Em que isso se desfaz:
Não funciona para várias notações científicas e / ou exponenciais (por exemplo, 1.2E3, 10 ^ 3, etc.) - ambas retornarão Falso. Também não acho que outras respostas tenham acomodado isso, e até o Python 3.8 tem opiniões inconsistentes, pois type(1E2)dá <class 'float'>que type(10^2)dá<class 'int'> .
Uma entrada de string vazia fornece True.
Portanto, não funcionará para todas as entradas possíveis, mas se você puder excluir notação científica, notação exponencial e seqüências de caracteres vazias, é uma verificação de linha única OK que retorna Falsese x não for um número inteiro eTrue se x for um número inteiro.
Não sei se é python, mas é uma linha e é relativamente claro o que o código faz.
Tentar / exceto parece andar no gramado de alguém (tentar) e, em seguida, se / quando eles notarem e ficarem bravos (exceção), você se desculpar (lida com a exceção), enquanto meu all(xi in '1234567890' for xi in x])padrão parece mais pedir permissão para atravessar o gramado. Não estou emocionado por pedir permissão, mas aqui estamos.
Adivinha o que replacefaz? Além disso, isso aceitará incorretamente 5-2, por exemplo.
Ry-
Irá lançar um IndexError ses='-'
Anti Earth
s = '-'; s.replace ('-', '') .isdigit () -> False
Vladyslav Savchenko
2
Gostei muito do post do Shavais, mas adicionei mais um caso de teste (e a função isdigit () integrada):
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 notin numbers:returnFalsereturnTruedef isInt_Digit(v):
v = str(v).strip()return v.isdigit()
Os dois casos de teste que adicionei (isInt_loop e isInt_digit) passam exatamente nos mesmos casos de teste (ambos aceitam números inteiros não assinados), mas achei que as pessoas poderiam ser mais espertas ao modificar a implementação da string (isInt_loop) em oposição ao isdigit incorporado (), então eu a incluí, mesmo que haja uma pequena diferença no tempo de execução. (e os dois métodos superam muito o resto, mas não lidam com o material extra: "./+/-")
Além disso, achei interessante notar que o regex (método isInt_re2) superou a comparação de cadeias no mesmo teste que foi realizado pelo Shavais em 2012 (atualmente em 2018). Talvez as bibliotecas regex tenham sido melhoradas?
Esta é provavelmente a maneira mais direta e pitônica de abordá-la na minha opinião. Eu não vi essa solução e é basicamente o mesmo que o regex, mas sem o regex.
Aqui está uma função que analisa sem gerar erros. Ele lida com casos óbvios de retorno Noneem caso de falha (lida com até 2000 sinais '- / +' por padrão no CPython!):
#!/usr/bin/env pythondef get_int(number):
splits = number.split('.')if len(splits)>2:# too many splitsreturnNoneif len(splits)==2and splits[1]:# handle decimal part recursively :-)if get_int(splits[1])!=0:returnNone
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)
Alguns testes:
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)))
Avalie com segurança um nó de expressão ou uma sequência que contém um literal Python ou exibição de contêiner. A cadeia ou nó fornecido pode consistir apenas nas seguintes estruturas literais do Python: cadeias, bytes, números, tuplas, listas, dictos, conjuntos, booleanos e Nenhum.
Devo observar que isso gerará uma ValueErrorexceção quando chamado contra qualquer coisa que não constitua um literal Python. Como a pergunta foi feita por uma solução sem tentativa / exceção, eu tenho uma solução do tipo Kobayashi-Maru para isso:
from ast import literal_eval
from contextlib import suppress
def is_int(s):with suppress(ValueError):return isinstance(literal_eval(s), int)returnFalse
Eu acho que a pergunta está relacionada à velocidade, já que o try / except tem uma penalidade de tempo:
dados de teste
Primeiro, criei uma lista de 200 strings, 100 strings com falha e 100 strings numéricas.
from random import shuffle
numbers =[u'+1']*100
nonumbers =[u'1abc']*100
testlist = numbers + nonumbers
shuffle(testlist)
testlist = np.array(testlist)
solução numpy (funciona apenas com matrizes e unicode)
O np.core.defchararray.isnumeric também pode trabalhar com seqüências unicode, np.core.defchararray.isnumeric(u'+12')mas ele retorna e matriz. Portanto, é uma boa solução se você tiver que fazer milhares de conversões e tiver dados ausentes ou dados não numéricos.
import numpy as np
%timeit np.core.defchararray.isnumeric(testlist)10000 loops, best of 3:27.9µs per loop # 200 numbers per loop
tente / exceto
def check_num(s):try:
int(s)returnTrueexcept:returnFalsedef 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
Isso funciona se você não colocar uma string que não seja um número.
E também (eu esqueci de colocar a parte de verificação do número.), Existe uma função que verifica se a sequência é um número ou não. É str.isdigit (). Aqui está um exemplo:
Respostas:
Se você está realmente irritado com o uso de
try/except
s em todo o lugar, basta escrever uma função auxiliar:Vai ser MUITO mais código para cobrir exatamente todas as strings que o Python considera inteiros. Eu digo apenas seja pythonic neste.
fonte
>>> print RepresentsInt(10.0)
True
>>> print RepresentsInt(10.06)
True
com números inteiros positivos você pode usar
.isdigit
:embora não funcione com números inteiros negativos. suponha que você possa tentar o seguinte:
não funcionará com o
'16.0'
formato, que é semelhante aoint
vazamento nesse sentido.editar :
fonte
u'²'.isdigit()
é verdade, masint(u'²')
gera ValueError. Use emu.isdecimal()
vez disso.str.isdigit()
é dependente da localidade no Python 2. #check_int('')
irá gerar uma exceção em vez de voltarFalse
Você sabe, eu descobri (e testei isso várias vezes) que tentar / exceto não funciona tão bem, por qualquer motivo. Frequentemente, tento várias maneiras de fazer as coisas e acho que nunca encontrei um método que use try / exceto para executar o melhor dos testados; na verdade, parece-me que esses métodos geralmente se aproximam do pior, se não o pior. Não em todos os casos, mas em muitos casos. Eu sei que muitas pessoas dizem que é o caminho "Pythonic", mas essa é uma área em que me separo deles. Para mim, não é muito eficiente nem muito elegante; portanto, costumo usá-lo apenas para capturar e reportar erros.
Eu ia entender que PHP, perl, ruby, C e até mesmo o maldito shell têm funções simples para testar uma string para um número inteiro, mas a devida diligência em verificar essas suposições me levou a sério! Aparentemente, essa falta é uma doença comum.
Aqui está uma edição rápida e suja da postagem de Bruno:
Aqui estão os resultados da comparação de desempenho:
O método AC pode digitalizá-lo uma vez e concluir. O método AC que varre a string uma vez seria a coisa certa a fazer, eu acho.
EDITAR:
Atualizei o código acima para trabalhar no Python 3.5 e incluir a função check_int da resposta mais votada no momento e para usar o regex mais popular atual que posso encontrar para testar o número inteiro. Esse regex rejeita seqüências de caracteres como 'abc 123'. Eu adicionei 'abc 123' como um valor de teste.
É muito interessante para mim observar, neste ponto, que NENHUMA das funções testadas, incluindo o método try, a popular função check_int e o regex mais popular para testar a integração de números inteiros, retornam as respostas corretas para todos os valores de teste (bem, dependendo das respostas corretas, consulte os resultados do teste abaixo).
A função interna int () silenciosamente trunca a parte fracionária de um número de ponto flutuante e retorna a parte inteira antes do decimal, a menos que o número do ponto flutuante seja primeiro convertido em uma seqüência de caracteres.
A função check_int () retorna false para valores como 0.0 e 1.0 (que tecnicamente são números inteiros) e retorna true para valores como '06'.
Aqui estão os resultados dos testes atuais (Python 3.5):
Só agora eu tentei adicionar esta função:
Ele executa quase tão bem quanto check_int (0.3486) e retorna true para valores como 1.0 e 0.0 e +1.0 e 0. e .0 e assim por diante. Mas também retorna verdadeiro para '06', então. Escolha seu veneno, eu acho.
fonte
try
é mais eficiente: isInt_try: 0.6552 / isInt_str: 0.6396 / isInt_re: 1.0296 / isInt_re2: 0.5168.str.isdigit()
deve fazer o truque.Exemplos:
EDIT : Como o @BuzzMoschetti apontou, esse caminho falhará no número negativo (por exemplo, "-23" ). Caso seu input_num possa ser menor que 0, use re.sub (regex_search, regex_replace, contents) antes de aplicar str.isdigit () . Por exemplo:
fonte
Use uma expressão regular:
Se você deve aceitar frações decimais também:
Para melhorar o desempenho, se você estiver fazendo isso com frequência, compile a expressão regular apenas uma vez usando
re.compile()
.fonte
A solução RegEx adequada combinaria as idéias de Greg Hewgill e Nowell, mas não usaria uma variável global. Você pode fazer isso anexando um atributo ao método Além disso, eu sei que é desagradável colocar as importações em um método, mas o que eu desejo é um efeito de "módulo lento" como http://peak.telecommunity.com/DevCenter/Importing#lazy-imports
editar: Minha técnica favorita até agora é usar exclusivamente métodos do objeto String.
E para os membros menos aventureiros da classe, aqui está a saída:
fonte
Portanto, sua função seria:
fonte
A abordagem de Greg Hewgill estava faltando alguns componentes: o "^" principal para corresponder apenas ao início da string e compilando o re antecipadamente. Mas essa abordagem permitirá que você evite uma tentativa: exept:
Eu estaria interessado em saber por que você está tentando evitar a tentativa: exceto?
fonte
Eu tenho que fazer isso o tempo todo e tenho uma aversão leve, mas reconhecidamente irracional, ao uso do padrão try / except. Eu uso isso:
Ele não acomoda números negativos; portanto, você pode retirar um sinal de menos (se houver) e verificar se o resultado inclui dígitos de 0 a 9:
Você também pode passar x para str () se não tiver certeza de que a entrada é uma string:
Há pelo menos dois casos (edge?) Em que isso se desfaz:
type(1E2)
dá<class 'float'>
quetype(10^2)
dá<class 'int'>
.Portanto, não funcionará para todas as entradas possíveis, mas se você puder excluir notação científica, notação exponencial e seqüências de caracteres vazias, é uma verificação de linha única OK que retorna
False
se x não for um número inteiro eTrue
se x for um número inteiro.Não sei se é python, mas é uma linha e é relativamente claro o que o código faz.
fonte
all(xi in '1234567890' for xi in x])
padrão parece mais pedir permissão para atravessar o gramado. Não estou emocionado por pedir permissão, mas aqui estamos.eu acho que
seria melhor reescrever para:
porque s [1:] também cria uma nova string
Mas uma solução muito melhor é
fonte
replace
faz? Além disso, isso aceitará incorretamente5-2
, por exemplo.s='-'
Gostei muito do post do Shavais, mas adicionei mais um caso de teste (e a função isdigit () integrada):
e supera consistentemente os tempos do resto:
usando python 2.7 normal:
Os dois casos de teste que adicionei (isInt_loop e isInt_digit) passam exatamente nos mesmos casos de teste (ambos aceitam números inteiros não assinados), mas achei que as pessoas poderiam ser mais espertas ao modificar a implementação da string (isInt_loop) em oposição ao isdigit incorporado (), então eu a incluí, mesmo que haja uma pequena diferença no tempo de execução. (e os dois métodos superam muito o resto, mas não lidam com o material extra: "./+/-")
Além disso, achei interessante notar que o regex (método isInt_re2) superou a comparação de cadeias no mesmo teste que foi realizado pelo Shavais em 2012 (atualmente em 2018). Talvez as bibliotecas regex tenham sido melhoradas?
fonte
Esta é provavelmente a maneira mais direta e pitônica de abordá-la na minha opinião. Eu não vi essa solução e é basicamente o mesmo que o regex, mas sem o regex.
fonte
set(input_string) == set(string.digits)
se pularmos'-+ '
no começo e.0
,E-1
no final.Aqui está uma função que analisa sem gerar erros. Ele lida com casos óbvios de retorno
None
em caso de falha (lida com até 2000 sinais '- / +' por padrão no CPython!):Alguns testes:
Resultados:
Para suas necessidades, você pode usar:
fonte
Sugiro o seguinte:
Dos documentos :
Devo observar que isso gerará uma
ValueError
exceção quando chamado contra qualquer coisa que não constitua um literal Python. Como a pergunta foi feita por uma solução sem tentativa / exceção, eu tenho uma solução do tipo Kobayashi-Maru para isso:¯ \ _ (ツ) _ / ¯
fonte
Eu tenho uma possibilidade que não usa int e não deve gerar uma exceção, a menos que a string não represente um número
Ele deve funcionar para qualquer tipo de string que flutue aceite, positiva, negativa, notação de engenharia ...
fonte
Eu acho que a pergunta está relacionada à velocidade, já que o try / except tem uma penalidade de tempo:
dados de teste
Primeiro, criei uma lista de 200 strings, 100 strings com falha e 100 strings numéricas.
solução numpy (funciona apenas com matrizes e unicode)
O np.core.defchararray.isnumeric também pode trabalhar com seqüências unicode,
np.core.defchararray.isnumeric(u'+12')
mas ele retorna e matriz. Portanto, é uma boa solução se você tiver que fazer milhares de conversões e tiver dados ausentes ou dados não numéricos.tente / exceto
Parece que a solução numpy é muito mais rápida.
fonte
Se você deseja aceitar apenas dígitos ASCII inferiores, aqui estão os testes para fazer isso:
Python 3.7+:
(u.isdecimal() and u.isascii())
Python <= 3.6:
(u.isdecimal() and u == str(int(u)))
Outras respostas sugerem o uso de
.isdigit()
ou,.isdecimal()
mas ambos incluem alguns caracteres unicode superiores , como'٢'
(u'\u0662'
):fonte
int()
.Tente isso:
Isso funciona se você não colocar uma string que não seja um número.
E também (eu esqueci de colocar a parte de verificação do número.), Existe uma função que verifica se a sequência é um número ou não. É str.isdigit (). Aqui está um exemplo:
Se você chamar a.isdigit (), ele retornará True.
fonte
2
atribuídoa
.