Reparto de enteros generalizado en Python

8

Antecedentes

Tengo una cadena en Python que quiero convertir a un entero. Normalmente, solo usaría int:

>>> int("123")
123

Desafortunadamente, este método no es muy robusto, ya que solo acepta cadenas que coinciden -?[0-9]+(después de eliminar cualquier espacio en blanco inicial o final). Por ejemplo, no puede manejar la entrada con un punto 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'

Y ciertamente no puede manejar esto:

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

Por otro lado, exactamente este comportamiento se puede tener sin problemas en Perl, PHP e incluso el humilde QBasic:

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

Pregunta

Aquí está mi esfuerzo más corto en este "generalizado int" en Python. Son 50 bytes, suponiendo que la cadena original está en sy el resultado debería terminar en i:

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

Bastante sencillo, pero el try/ exceptbit es feo y largo. ¿Hay alguna forma de acortarlo?

Detalles

Las respuestas deben hacer todo lo siguiente:

  • Comience con una cadena s; termina con su valor entero en i.
  • El entero es la primera serie de dígitos en la cadena. Todo lo que sigue se ignora, incluidos otros dígitos si vienen después de no dígitos.
  • Los ceros iniciales en la entrada son válidos.
  • Cualquier cadena que no comience con un número entero válido tiene un valor de 0.

Se prefieren las siguientes características , aunque no son necesarias:

  • Un solo -signo inmediatamente antes de los dígitos hace que el entero sea negativo.
  • Ignora los espacios en blanco antes y después del número.
  • Funciona igualmente bien en Python 2 o 3.

(Nota: mi código anterior cumple con todos estos criterios).

Casos de prueba

"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
fuente
Algo relacionado: codegolf.stackexchange.com/questions/28783/… (pero allí se indicó explícitamente que la entrada sería enteros formados correctamente).
DLosc
1
¿Qué debería "12abc3"dar?
orlp
@orlp: 12es análogo al "123.45"caso.
DLosc
(lambda(x)(or(parse-integer x :junk-allowed t)0))(Common Lisp, 49 bytes): solo se publica como un comentario, ya que está integrado.
Coredump
1
@coredump :junk-allowed--ha, eso es genial! Hubiera hecho de esto un desafío general de golf, si no fuera por el hecho de que la respuesta en muchos idiomas es trivial. Pero gracias por el Lisp. : ^)
DLosc

Respuestas:

4

40 bytes

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

y puedes hacer negativos para 8 caracteres más:

import re;i=int((re.findall("^-?\d+",s)+[0])[0])
KSab
fuente
@DLosc Ah, tienes razón, aparentemente no probé el segundo lo suficientemente bien. El momento 'aha' fue cuando me di cuenta de que algunas funciones de expresión regular de Python devuelven cadenas no MatchObjects
KSab
1
import re;i=int((re.findall("^-?\d+",s)+[0])[0])funciona, por 48 bytes.
DLosc
6

Pitón 2, 47 , 46

No es tan corto como usar expresiones regulares, pero pensé que era entretenido y oscuro.

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

-1 debido a KSab: strcon un número entero grande funciona mejor que el operador repr, ya que no pone un Lextremo.

Feersum
fuente
2
puede afeitarse un byte utilizando el str(1<<68)interior de la banda
KSab
Guau. Entretenido oscuro es correcto! (Esto solo maneja números no negativos, ¿correcto?)
DLosc
Otra ventaja de la sugerencia de @ KSab es la compatibilidad con Python 3.
DLosc