Fundição inteira generalizada em Python

8

fundo

Eu tenho uma seqüência de caracteres em Python que eu quero converter em um número inteiro. Normalmente, eu usaria apenas int:

>>> int("123")
123

Infelizmente, esse método não é muito robusto, pois aceita apenas cadeias correspondentes -?[0-9]+(após remover qualquer espaço em branco à esquerda ou à direita). Por exemplo, ele não pode manipular a entrada com um ponto decimal:

>>> int("123.45")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '123.45'

E certamente não pode lidar com isso:

>>> int("123abc?!")

Por outro lado, exatamente esse comportamento pode ser tido sem problemas em Perl, PHP e até o humilde QBasic:

INT(VAL("123abc"))   ' 123

Questão

Aqui está o meu menor esforço neste "generalizado int" em Python. São 50 bytes, supondo que a string original esteja se o resultado deve terminar em i:

n="";i=0
for c in s:
 n+=c
 try:i=int(n)
 except:0

Bastante simples, mas a try/ exceptbit é feio e longo prazo. Existe alguma maneira de reduzi-lo?

Detalhes

As respostas precisam fazer o seguinte:

  • Comece com uma string s; termina com seu valor inteiro em i.
  • O número inteiro é a primeira sequência de dígitos na sequência. Tudo depois disso é ignorado, incluindo outros dígitos, se vierem depois de não dígitos.
  • Os zeros à esquerda na entrada são válidos.
  • Qualquer sequência que não comece com um número inteiro válido tem um valor de 0.

Os seguintes recursos são preferidos , embora não sejam necessários:

  • Um único - sinal imediatamente antes dos dígitos torna o número inteiro negativo.
  • Ignora os espaços em branco antes e depois do número.
  • Funciona igualmente bem em Python 2 ou 3.

(Nota: meu código acima atende a todos esses critérios.)

Casos de teste

"0123"   -> 123
"123abc" -> 123
"123.45" -> 123
"abc123" -> 0
"-123"   -> -123 (or 0 if negatives not handled)
"-1-2"   -> -1 (or 0 if negatives not handled)
"--1"    -> 0
""       -> 0
DLosc
fonte
Um pouco relacionado: codegolf.stackexchange.com/questions/28783/… (mas foi declarado explicitamente que a entrada seria um número inteiro formado corretamente).
DLosc 27/05
1
O que deveria "12abc3"dar?
orlp 27/05
@orlp --é 12análogo ao "123.45"caso.
DLosc 27/05
(lambda(x)(or(parse-integer x :junk-allowed t)0))(Lisp comum, 49 bytes) - Publicado somente como um comentário, pois está embutido.
Coredump 27/05
1
@coredump :junk-allowed--ha, isso é ótimo! Eu teria feito disso um desafio geral ao golfe, não fosse o fato de que a resposta em muitos idiomas é trivial. Mas obrigado pelo Lisp. : ^)
DLosc

Respostas:

4

40 bytes

import re;i=int("0"+re.split("\D",s)[0])

e você pode fazer negativos por mais 8 caracteres:

import re;i=int((re.findall("^-?\d+",s)+[0])[0])
KSab
fonte
@DLosc Ah, você está certo, aparentemente não testou o segundo suficientemente bem. O momento 'aha' foi quando eu percebi algumas funções python regex retornar cordas não MatchObjects
KSab
1
import re;i=int((re.findall("^-?\d+",s)+[0])[0])funciona, por 48 bytes.
DLosc 27/05
6

Pitão 2, 47 , 46

Não é tão curto quanto usar regex, mas achei que era divertido e obscuro.

i=int(('0%sx'%s)[:~len(s.lstrip(str(1<<68)))])

-1 devido ao KSab - strcom um número inteiro grande funciona melhor que o operador repr, pois não coloca um Lfinal.

feersum
fonte
2
você pode raspar um byte usando str(1<<68)dentro do lstrip
KSab
Uau. Divertidamente obscuro é certo! (Isso só lida com números não negativos, correto?)
DLosc
Outro bônus da sugestão do @ KSab é a compatibilidade com o Python 3.
DLosc 27/05