¿Cómo puedo verificar si una cadena representa un int, sin usar try / except?
467
¿Hay alguna manera de saber si una cadena representa un número entero (por ejemplo '3', '-17'pero no '3.14'o 'asfasfas') sin usar un mecanismo try / except?
¿Por qué ambos intentan hacer esto "de la manera difícil"? ¿Qué hay de malo en probar / excepto?
S.Lott
55
Sí, ¿qué hay de malo en probar / excepto? Es mejor pedir perdón que permiso.
mk12
53
Me preguntaría por qué esta simple cosa requiere probar / excepto. El sistema de excepción es una bestia compleja, pero este es un problema simple.
Aivar
13
@Aivar deja de difundir FUD. Un solo bloque try / except ni siquiera se aproxima a "complejo".
Tríptico
47
Sin embargo, no es realmente FUD. Estaría escribiendo efectivamente 4 líneas de código, esperando que explote algo, detectando esa excepción y haciendo lo predeterminado, en lugar de usar un solo trazo.
andersonvom
Respuestas:
398
Si realmente está molesto por usar try/excepts en todo el lugar, simplemente escriba una función auxiliar:
Entonces, ¿es pitónico resolver un problema simple con un mecanismo complejo? Existe un algoritmo para detectar la función interna escrita "int" de int. No veo por qué no se expone esto como una función booleana.
Aivar
79
@Aivar: esta función de 5 líneas no es un mecanismo complejo.
Supongo que es "pitónico" en el sentido de que si Python piensa que la cadena es un int, también lo hace su programa. Si Python cambia, también lo hace su programa, y sin cambiar una sola línea de código. Hay algo de valor en eso. Puede ser lo correcto según las circunstancias.
Shavais
57
No sé por qué esta es la respuesta aceptada o tiene tantos votos positivos, ya que esto es exactamente lo contrario de lo que está pidiendo OP.
esto no maneja "+17" sin un caso especial adicional.
Bryan Oakley
1
Debe probar AMBOS casos: lambda s: s.isdigit () o (s.startswith ('-') y s [1:]. Isdigit ())
robar el
44
@Roberto: ¡por supuesto que deberías! ¡y estoy seguro de que eres capaz de hacerlo!
SilentGhost
22
nota: u'²'.isdigit()es cierto pero int(u'²')aumenta ValueError. Usar en su u.isdecimal()lugar. str.isdigit()depende de la configuración regional en Python 2.
jfs
44
check_int('')False
provocará
97
Sabes, he descubierto (y he probado esto una y otra vez) que intentar / excepto no funciona tan bien, por cualquier razón. Frecuentemente intento varias formas de hacer las cosas, y no creo haber encontrado un método que use try / except para obtener el mejor rendimiento de los probados, de hecho, me parece que esos métodos generalmente se han acercado al lo peor, si no lo peor. No en todos los casos, pero en muchos casos. Sé que mucha gente dice que es la forma "Pitónica", pero esa es un área donde me separo de ellos. Para mí, no es muy eficiente ni muy elegante, por lo tanto, tiendo a usarlo solo para capturar errores e informar.
Iba a quejarme de que PHP, perl, ruby, C e incluso el maldito shell tienen funciones simples para probar una cadena de entero, ¡pero la diligencia debida en verificar esas suposiciones me hizo tropezar! Al parecer, esta falta es una enfermedad común.
Aquí hay una edición rápida y sucia de la publicación 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 reifnot 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 - t1def 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))
Aquí están los resultados de la comparación de rendimiento:
El método de CA podría escanearlo una vez, y listo. Creo que el método AC que escanea la cadena una vez sería lo correcto.
EDITAR:
He actualizado el código anterior para que funcione en Python 3.5, para incluir la función check_int de la respuesta más votada actualmente, y para usar la expresión regular más popular actual que puedo encontrar para probar el integer-hood. Esta expresión regular rechaza cadenas como 'abc 123'. He agregado 'abc 123' como valor de prueba.
Es muy interesante para mí notar, en este punto, que NINGUNA de las funciones probadas, incluido el método try, la popular función check_int y la expresión regular más popular para probar el entero, devuelve las respuestas correctas para todas las valores de la prueba (bueno, dependiendo de cuáles creas que son las respuestas correctas; mira los resultados de la prueba a continuación).
La función integrada int () trunca silenciosamente la parte fraccionaria de un número de coma flotante y devuelve la parte entera antes del decimal, a menos que el número de coma flotante se convierta primero en una cadena.
La función check_int () devuelve falso para valores como 0.0 y 1.0 (que técnicamente son enteros) y devuelve verdadero para valores como '06'.
Aquí están los resultados de la prueba actual (Python 3.5):
Funciona casi tan bien como check_int (0.3486) y devuelve verdadero para valores como 1.0 y 0.0 y +1.0 y 0. y .0 y así sucesivamente. Pero también devuelve verdadero para '06', entonces. Elige tu veneno, supongo.
Quizás parte de esto proviene del hecho de que un entero es un poco arbitrario en sí mismo. Un sistema de programación no puede darse el lujo de asumir que siempre será una representación decimal. 0x4df, es un número entero válido en algunos lugares, y 0891 no está en otros. Me da miedo pensar qué podría surgir dado unicode en este tipo de controles.
PlexQ
3
+1 para el tiempo. Estoy de acuerdo en que todo este asunto de excepción no es realmente elegante para una pregunta tan simple. Esperarías un método auxiliar de construcción para un problema tan común ...
RickyA
99
Sé que este hilo está básicamente inactivo, pero +1 por considerar el tiempo de ejecución. La longitud de la línea no siempre es indicativa de la complejidad subyacente; y seguro, un try / except puede parecer simple (y fácil de leer, que también es importante), pero es una operación costosa. Yo diría que la jerarquía de preferencias siempre debería tener un aspecto similar al siguiente: 1. Una solución explícita fácil de leer (SilentGhost's). 2. Una solución implícita fácil de leer (tríptico). 3. No hay tres.
Eric Humphrey
1
Gracias por sus investigaciones exhaustivas sobre un tema aparentemente insignificante. Iré con isInt_str (), pythonic o no. Lo que me molesta es que no he encontrado nada sobre el significado de v.find ('..'). ¿Es algún tipo de sintaxis de búsqueda especial o un caso de borde de una cadena numérica?
JackLeEmmerdeur
3
Sí, un poco anticuado pero sigue siendo un análisis realmente agradable y relevante. En Python 3.5 tryes más eficiente: isInt_try: 0.6552 / isInt_str: 0.6396 / isInt_re: 1.0296 / isInt_re2: 0.5168.
EDITAR : Como señaló @BuzzMoschetti, esta forma fallará para el número menos (por ejemplo, "-23" ). En caso de que su input_num pueda ser menor que 0, use re.sub (regex_search, regex_replace, contents) antes de aplicar str.isdigit () . Por ejemplo:
import re
input_num ="-23"
input_num = re.sub("^-","", input_num)## "^" indicates to remove the first "-" only
str.isdigit(input_num)## True
@ BuzzMoschetti tienes razón. Una forma rápida de solucionarlo es eliminar el signo menos mediante re.replace (regex_search, regex_replace, contenido) antes de aplicar str.isdigit ()
+1: revela que esto es horriblemente complejo y costoso en comparación con try / except.
S.Lott
2
Creo que esta es esencialmente una versión más lenta y personalizada de la solución 'isnumeric' que ofrece @SilentGhost.
Greg
@Greg: Dado que @SilentGhost no cubre los signos correctamente, esta versión realmente funciona.
S.Lott
1
@ S.Lott: seguramente, cualquier persona capaz de publicar en SO, podría extender mi ejemplo para cubrir carteles.
SilentGhost
2
las expresiones regulares son sobre lo más complejo y oscuro que existe, encuentro que la simple verificación anterior es sustancialmente más clara, incluso si creo que todavía es feo, esto es más feo.
PlexQ
18
La solución RegEx adecuada combinaría las ideas de Greg Hewgill y Nowell, pero no utilizaría una variable global. Puede lograr esto adjuntando un atributo al método. Además, sé que está mal visto poner las importaciones en un método, pero lo que busco es un efecto de "módulo perezoso" como http://peak.telecommunity.com/DevCenter/Importing#lazy-imports
editar: mi técnica favorita hasta ahora es utilizar exclusivamente métodos del 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 reifnot 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))
Y para los miembros menos aventureros de la clase, aquí está el resultado:
I compile only once.Remove this line when you are confident in that.0is an integer is an integre1is an integer is an integre-1is an integer is an integre1.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 integre1.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
Estoy de acuerdo en que mi conjunto de pruebas es excesivo. Me gusta demostrar que mi código funciona cuando lo escribo. ¿Pero crees que mi función isInteger es exagerada? Seguramente no.
Bruno Bronosky
1
Acabo de recibir un voto negativo sin comentarios. ¿Qué pasa con la gente? Entiendo que los millennials ahora usan "Me gusta" como "recibos de lectura". ¿Pero ahora están usando los votos negativos como marcadores "no es el método que elegí"? Tal vez no se dan cuenta de que resta 2 puntos de SU PROPIA reputación para rechazar una respuesta. SO / SE hace eso para alentar la votación negativa solo debido a información errónea, en cuyo caso espero que dejes un comentario .
Al enfoque de Greg Hewgill le faltaban algunos componentes: el "^" inicial para coincidir solo con el inicio de la cadena y compilar el re de antemano. Pero este enfoque le permitirá evitar un intento: exept:
import re
INT_RE = re.compile(r"^[-]?\d+$")defRepresentsInt(s):return INT_RE.match(str(s))isnotNone
Me interesaría por qué intenta evitar intentar: ¿excepto?
Una cuestión de estilo. Creo que "probar / excepto" debería usarse solo con errores reales, no con el flujo normal del programa.
Adam Matan
2
@Udi Pasmon: Python hace un uso bastante intenso de try / except para el flujo de programa "normal". Por ejemplo, cada iterador se detiene con una excepción planteada.
S.Lott
3
-1: Aunque su sugerencia para compilar la expresión regular es correcta, está equivocado al criticar a Greg en el otro sentido: re.match coincide con el inicio de la cadena, por lo que el ^ en el patrón es realmente redundante. (Esto es diferente cuando usas re.search).
ThomasH
S.Lott: ¿se considera un flujo razonable en Python? ¿Cómo difiere esto de otros idiomas? Quizás valga una pregunta por separado.
Adam Matan
1
El uso intensivo de Python de try / except se ha cubierto aquí en SO. Intente buscar '[python] excepto'
S.Lott
4
Tengo que hacer esto todo el tiempo, y tengo una aversión leve pero ciertamente irracional a usar el patrón try / except. Yo uso esto:
all([xi in'1234567890'for xi in x])
No admite números negativos, por lo que puede eliminar un signo menos (si lo hay) y luego verificar si el resultado comprende dígitos del 0 al 9:
all([xi in'1234567890'for xi in x.replace('-','',1)])
También puede pasar x a str () si no está seguro de que la entrada es una cadena:
all([xi in'1234567890'for xi in str(x).replace('-','',1)])
Hay al menos dos casos (¿de borde?) En los que esto se desmorona:
No funciona para varias notaciones científicas y / o exponenciales (por ejemplo, 1.2E3, 10 ^ 3, etc.); ambas devolverán False. Tampoco creo que otras respuestas acomodaran esto, e incluso Python 3.8 tiene opiniones inconsistentes, ya que type(1E2)da <class 'float'>mientras type(10^2)da <class 'int'>.
Una entrada de cadena vacía da True.
Por lo tanto, no funcionará para cada entrada posible, pero si puede excluir la notación científica, la notación exponencial y las cadenas vacías, es una comprobación de una línea correcta que devuelve Falsesi x no es un número entero y Truesi x es un número entero.
No sé si es pitónico, pero es una línea y está relativamente claro lo que hace el código.
Intentar / excepto parece caminar sobre el césped de alguien (intentar) y luego si / cuando se dan cuenta y se enojan (excepción) te disculpas (manejas la excepción), mientras que mi all(xi in '1234567890' for xi in x])patrón parece más pedir permiso para caminar por el césped. No estoy emocionado de pedir permiso, pero aquí estamos.
¿Adivina qué replacehace? Además, esto aceptará incorrectamente 5-2, por ejemplo.
Ry-
Lanzará un IndexError sis='-'
Anti Earth
s = '-'; s.replace ('-', '') .isdigit () -> False
Vladyslav Savchenko
2
Realmente me gustó la publicación de Shavais, pero agregué un caso de prueba más (y la función isdigit () incorporada):
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()
y supera significativamente los tiempos del resto:
Los dos casos de prueba que agregué (isInt_loop y isInt_digit) pasan exactamente los mismos casos de prueba (ambos solo aceptan enteros sin signo), pero pensé que las personas podrían ser más inteligentes al modificar la implementación de la cadena (isInt_loop) en lugar del isdigit incorporado (), así que lo incluí, aunque haya una ligera diferencia en el tiempo de ejecución. (y ambos métodos superan mucho a todo lo demás, pero no manejan las cosas adicionales: "./+/-")
Además, me pareció interesante observar que la expresión regular (método isInt_re2) superó la comparación de cadenas en la misma prueba que realizó Shavais en 2012 (actualmente 2018). ¿Quizás las bibliotecas de expresiones regulares han sido mejoradas?
Esta es probablemente la forma más directa y pitónica de abordarlo en mi opinión. No vi esta solución y es básicamente la misma que la expresión regular, pero sin la expresión regular.
Aquí hay una función que analiza sin generar errores. Maneja retornos de casos obvios en caso Nonede falla (maneja hasta 2000 signos '- / +' por defecto en 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)
Algunas pruebas:
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)))
Evalúe de forma segura un nodo de expresión o una cadena que contenga un literal de Python o una pantalla de contenedor. La cadena o nodo proporcionado solo puede consistir en las siguientes estructuras literales de Python: cadenas, bytes, números, tuplas, listas, dictos, conjuntos, booleanos y Ninguno.
Debo señalar que esto generará una ValueErrorexcepción cuando se invoque contra cualquier cosa que no constituya un literal de Python. Como la pregunta pedía una solución sin probar / excepto, tengo una solución de tipo Kobayashi-Maru para eso:
from ast import literal_eval
from contextlib import suppress
def is_int(s):with suppress(ValueError):return isinstance(literal_eval(s), int)returnFalse
Supongo que la pregunta está relacionada con la velocidad ya que el try / except tiene una penalización de tiempo:
datos de prueba
Primero, creé una lista de 200 cadenas, 100 cadenas defectuosas y 100 cadenas numéricas.
from random import shuffle
numbers =[u'+1']*100
nonumbers =[u'1abc']*100
testlist = numbers + nonumbers
shuffle(testlist)
testlist = np.array(testlist)
solución numpy (solo funciona con matrices y unicode)
np.core.defchararray.isnumeric también puede funcionar con cadenas unicode np.core.defchararray.isnumeric(u'+12')pero devuelve una matriz. Por lo tanto, es una buena solución si tiene que hacer miles de conversiones y le faltan datos o datos no 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
probar / excepto
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
Esto funciona si no pones una cadena que no sea un número.
Y también (olvidé poner la parte de verificación de número), hay una función que verifica si la cadena es un número o no. Es str.isdigit (). Aquí hay un ejemplo:
Respuestas:
Si realmente está molesto por usar
try/except
s en todo el lugar, simplemente escriba una función auxiliar:Va a ser MUCHO más código para cubrir exactamente todas las cadenas que Python considera enteros. Yo digo que sea pitón en este caso.
fuente
>>> print RepresentsInt(10.0)
True
>>> print RepresentsInt(10.06)
True
con enteros positivos que podrías usar
.isdigit
:Sin embargo, no funciona con enteros negativos. supongamos que puede intentar lo siguiente:
no funcionará con el
'16.0'
formato, que es similar alint
casting en este sentido.editar :
fuente
u'²'.isdigit()
es cierto peroint(u'²')
aumenta ValueError. Usar en suu.isdecimal()
lugar.str.isdigit()
depende de la configuración regional en Python 2.check_int('')
False
Sabes, he descubierto (y he probado esto una y otra vez) que intentar / excepto no funciona tan bien, por cualquier razón. Frecuentemente intento varias formas de hacer las cosas, y no creo haber encontrado un método que use try / except para obtener el mejor rendimiento de los probados, de hecho, me parece que esos métodos generalmente se han acercado al lo peor, si no lo peor. No en todos los casos, pero en muchos casos. Sé que mucha gente dice que es la forma "Pitónica", pero esa es un área donde me separo de ellos. Para mí, no es muy eficiente ni muy elegante, por lo tanto, tiendo a usarlo solo para capturar errores e informar.
Iba a quejarme de que PHP, perl, ruby, C e incluso el maldito shell tienen funciones simples para probar una cadena de entero, ¡pero la diligencia debida en verificar esas suposiciones me hizo tropezar! Al parecer, esta falta es una enfermedad común.
Aquí hay una edición rápida y sucia de la publicación de Bruno:
Aquí están los resultados de la comparación de rendimiento:
El método de CA podría escanearlo una vez, y listo. Creo que el método AC que escanea la cadena una vez sería lo correcto.
EDITAR:
He actualizado el código anterior para que funcione en Python 3.5, para incluir la función check_int de la respuesta más votada actualmente, y para usar la expresión regular más popular actual que puedo encontrar para probar el integer-hood. Esta expresión regular rechaza cadenas como 'abc 123'. He agregado 'abc 123' como valor de prueba.
Es muy interesante para mí notar, en este punto, que NINGUNA de las funciones probadas, incluido el método try, la popular función check_int y la expresión regular más popular para probar el entero, devuelve las respuestas correctas para todas las valores de la prueba (bueno, dependiendo de cuáles creas que son las respuestas correctas; mira los resultados de la prueba a continuación).
La función integrada int () trunca silenciosamente la parte fraccionaria de un número de coma flotante y devuelve la parte entera antes del decimal, a menos que el número de coma flotante se convierta primero en una cadena.
La función check_int () devuelve falso para valores como 0.0 y 1.0 (que técnicamente son enteros) y devuelve verdadero para valores como '06'.
Aquí están los resultados de la prueba actual (Python 3.5):
Justo ahora intenté agregar esta función:
Funciona casi tan bien como check_int (0.3486) y devuelve verdadero para valores como 1.0 y 0.0 y +1.0 y 0. y .0 y así sucesivamente. Pero también devuelve verdadero para '06', entonces. Elige tu veneno, supongo.
fuente
try
es más eficiente: isInt_try: 0.6552 / isInt_str: 0.6396 / isInt_re: 1.0296 / isInt_re2: 0.5168.str.isdigit()
debería hacer el truco.Ejemplos:
EDITAR : Como señaló @BuzzMoschetti, esta forma fallará para el número menos (por ejemplo, "-23" ). En caso de que su input_num pueda ser menor que 0, use re.sub (regex_search, regex_replace, contents) antes de aplicar str.isdigit () . Por ejemplo:
fuente
Usa una expresión regular:
Si debe aceptar fracciones decimales también:
Para un mejor rendimiento, si está haciendo esto a menudo, compilar la expresión regular el uso de una sola vez
re.compile()
.fuente
La solución RegEx adecuada combinaría las ideas de Greg Hewgill y Nowell, pero no utilizaría una variable global. Puede lograr esto adjuntando un atributo al método. Además, sé que está mal visto poner las importaciones en un método, pero lo que busco es un efecto de "módulo perezoso" como http://peak.telecommunity.com/DevCenter/Importing#lazy-imports
editar: mi técnica favorita hasta ahora es utilizar exclusivamente métodos del objeto String.
Y para los miembros menos aventureros de la clase, aquí está el resultado:
fuente
Entonces su función sería:
fuente
Al enfoque de Greg Hewgill le faltaban algunos componentes: el "^" inicial para coincidir solo con el inicio de la cadena y compilar el re de antemano. Pero este enfoque le permitirá evitar un intento: exept:
Me interesaría por qué intenta evitar intentar: ¿excepto?
fuente
Tengo que hacer esto todo el tiempo, y tengo una aversión leve pero ciertamente irracional a usar el patrón try / except. Yo uso esto:
No admite números negativos, por lo que puede eliminar un signo menos (si lo hay) y luego verificar si el resultado comprende dígitos del 0 al 9:
También puede pasar x a str () si no está seguro de que la entrada es una cadena:
Hay al menos dos casos (¿de borde?) En los que esto se desmorona:
type(1E2)
da<class 'float'>
mientrastype(10^2)
da<class 'int'>
.Por lo tanto, no funcionará para cada entrada posible, pero si puede excluir la notación científica, la notación exponencial y las cadenas vacías, es una comprobación de una línea correcta que devuelve
False
si x no es un número entero yTrue
si x es un número entero.No sé si es pitónico, pero es una línea y está relativamente claro lo que hace el código.
fuente
all(xi in '1234567890' for xi in x])
patrón parece más pedir permiso para caminar por el césped. No estoy emocionado de pedir permiso, pero aquí estamos.Yo creo que
sería mejor reescribir a:
porque s [1:] también crea una nueva cadena
Pero la solución mucho mejor es
fuente
replace
hace? Además, esto aceptará incorrectamente5-2
, por ejemplo.s='-'
Realmente me gustó la publicación de Shavais, pero agregué un caso de prueba más (y la función isdigit () incorporada):
y supera significativamente los tiempos del resto:
usando el pitón normal 2.7:
Los dos casos de prueba que agregué (isInt_loop y isInt_digit) pasan exactamente los mismos casos de prueba (ambos solo aceptan enteros sin signo), pero pensé que las personas podrían ser más inteligentes al modificar la implementación de la cadena (isInt_loop) en lugar del isdigit incorporado (), así que lo incluí, aunque haya una ligera diferencia en el tiempo de ejecución. (y ambos métodos superan mucho a todo lo demás, pero no manejan las cosas adicionales: "./+/-")
Además, me pareció interesante observar que la expresión regular (método isInt_re2) superó la comparación de cadenas en la misma prueba que realizó Shavais en 2012 (actualmente 2018). ¿Quizás las bibliotecas de expresiones regulares han sido mejoradas?
fuente
Esta es probablemente la forma más directa y pitónica de abordarlo en mi opinión. No vi esta solución y es básicamente la misma que la expresión regular, pero sin la expresión regular.
fuente
set(input_string) == set(string.digits)
si saltamos'-+ '
al principio y.0
,E-1
al final.Aquí hay una función que analiza sin generar errores. Maneja retornos de casos obvios en caso
None
de falla (maneja hasta 2000 signos '- / +' por defecto en CPython):Algunas pruebas:
Resultados:
Para sus necesidades puede usar:
fuente
Sugiero lo siguiente:
De los documentos :
Debo señalar que esto generará una
ValueError
excepción cuando se invoque contra cualquier cosa que no constituya un literal de Python. Como la pregunta pedía una solución sin probar / excepto, tengo una solución de tipo Kobayashi-Maru para eso:¯ \ _ (ツ) _ / ¯
fuente
Tengo una posibilidad que no usa int en absoluto, y no debería generar una excepción a menos que la cadena no represente un número
Debería funcionar para cualquier tipo de cadena que acepte flotante, positiva, negativa, notación de ingeniería ...
fuente
Supongo que la pregunta está relacionada con la velocidad ya que el try / except tiene una penalización de tiempo:
datos de prueba
Primero, creé una lista de 200 cadenas, 100 cadenas defectuosas y 100 cadenas numéricas.
solución numpy (solo funciona con matrices y unicode)
np.core.defchararray.isnumeric también puede funcionar con cadenas unicode
np.core.defchararray.isnumeric(u'+12')
pero devuelve una matriz. Por lo tanto, es una buena solución si tiene que hacer miles de conversiones y le faltan datos o datos no numéricos.probar / excepto
Parece que la solución numpy es mucho más rápida.
fuente
Si solo desea aceptar dígitos con un ascii más bajo, aquí hay pruebas para hacerlo:
Python 3.7+:
(u.isdecimal() and u.isascii())
Python <= 3.6:
(u.isdecimal() and u == str(int(u)))
Otras respuestas sugieren usar
.isdigit()
o.isdecimal()
pero ambos incluyen algunos caracteres unicode superiores como'٢'
(u'\u0662'
):fuente
int()
.Uh .. Prueba esto:
Esto funciona si no pones una cadena que no sea un número.
Y también (olvidé poner la parte de verificación de número), hay una función que verifica si la cadena es un número o no. Es str.isdigit (). Aquí hay un ejemplo:
Si llama a a.isdigit (), devolverá True.
fuente
2
asignadoa
.