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?

is_int('3.14') = False
is_int('-7')   = True
Adam Matan
fonte
23
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:

def RepresentsInt(s):
    try: 
        int(s)
        return True
    except ValueError:
        return False

>>> print RepresentsInt("+123")
True
>>> print RepresentsInt("10.0")
False

Vai ser MUITO mais código para cobrir exatamente todas as strings que o Python considera inteiros. Eu digo apenas seja pythonic neste.

Tríptico
fonte
124
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.
Triptych
34
Exceto:>>> print RepresentsInt(10.0) True >>> print RepresentsInt(10.06) True
Dannid 12/12
5
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.

editar :

def check_int(s):
    if s[0] in ('-', '+'):
        return s[1:].isdigit()
    return s.isdigit()
SilentGhost
fonte
6
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 = [
    # 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))

Aqui estão os resultados da comparação de desempenho:

timings..
isInt_try:   0.6426
isInt_str:   0.7382
isInt_re:    1.1156
isInt_re2:   0.5344
check_int:   0.3452

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):

                  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   |

Só agora eu tentei adicionar esta função:

def isInt_float(s):
    try:
        return float(str(s)).is_integer()
    except:
        return False

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.

Shavais
fonte
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.
21416 Dave
40

str.isdigit() deve fazer o truque.

Exemplos:

str.isdigit("23") ## True
str.isdigit("abc") ## False
str.isdigit("23.4") ## False

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
Catbuilts
fonte
1
Porque -23 produz falso.
Buzz Moschetti
1
@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
def RepresentsInt(s):
    return re.match(r"[-+]?\d+$", s) is not None

Se você deve aceitar frações decimais também:

def RepresentsInt(s):
    return re.match(r"[-+]?\d+(\.0*)?$", s) is not None

Para melhorar o desempenho, se você estiver fazendo isso com frequência, compile a expressão regular apenas uma vez usando re.compile().

Greg Hewgill
fonte
19
+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 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))

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.
                             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
Bruno Bronosky
fonte
4
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 .
BrunoBruno19 / 01/18
5
>>> "+7".lstrip("-+").isdigit()
True
>>> "-7".lstrip("-+").isdigit()
True
>>> "7".lstrip("-+").isdigit()
True
>>> "13.4".lstrip("-+").isdigit()
False

Portanto, sua função seria:

def is_int(val):
   return val[1].isdigit() and val.lstrip("-+").isdigit()
alkos333
fonte
1
is_int ("2") gera IndexError.
anttikoo
4

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+$")
def RepresentsInt(s):
    return INT_RE.match(str(s)) is not None

Eu estaria interessado em saber por que você está tentando evitar a tentativa: exceto?

Nowell
fonte
1
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:

  1. 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)<class 'float'>que type(10^2)<class 'int'> .
  2. 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.

mRotten
fonte
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.
mRotten 29/04
3

eu acho que

s.startswith('-') and s[1:].isdigit()

seria melhor reescrever para:

s.replace('-', '').isdigit()

porque s [1:] também cria uma nova string

Mas uma solução muito melhor é

s.lstrip('+-').isdigit()
Vladyslav Savchenko
fonte
3
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 not in numbers:
            return False
    return True

def isInt_Digit(v):
    v = str(v).strip()
    return v.isdigit()

e supera consistentemente os tempos do resto:

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

usando python 2.7 normal:

$ python --version
Python 2.7.10

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?

brw59
fonte
1

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.

def is_int(test):
    import string
    return not (set(test) - set(string.digits))
Xenlyte
fonte
set(input_string) == set(string.digits)se pularmos '-+ 'no começo e .0, E-1no final.
JFS
1

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 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)

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)))

Resultados:

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

Para suas necessidades, você pode usar:

def int_predicate(number):
     return get_int(number) is not None
Reut Sharabani
fonte
1

Sugiro o seguinte:

import ast

def is_int(s):
    return isinstance(ast.literal_eval(s), int)

Dos documentos :

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)
    return False

¯ \ _ (ツ) _ / ¯

Jesko Hüttenhain
fonte
0

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

float(number)==float(number)//1

Ele deve funcionar para qualquer tipo de string que flutue aceite, positiva, negativa, notação de engenharia ...

agomcas
fonte
0

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)
    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

Parece que a solução numpy é muito mais rápida.

Carlos Vega
fonte
0

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'):

u = u'\u0662'     # '٢'
u.isdigit()       # True
u.isdecimal()     # True
u.isascii()       # False (Python 3.7+ only)
u == str(int(u))  # False
krubo
fonte
Isso não manipula valores negativos ou valores preenchidos com espaço em branco, os quais são tratados com precisão int().
ShadowRanger
-6

Tente isso:

def int_check(a):
    if int(a) == a:
        return True
    else:
        return False

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:

a = 2
a.isdigit()

Se você chamar a.isdigit (), ele retornará True.

HaulCozen
fonte
Eu acho que você precisa de aspas em torno do valor 2atribuído a.
Luke Woodward
1
Por que essa resposta não é a melhor? Responde exatamente à pergunta.
gafanhoto
6
-1 a pergunta: "Verifique se uma string representa um int, sem usar Try / Except?" para @Caroline Alexiou
jfs