¿Cómo puedo comprobar si una cadena contiene ALGUNA letra del alfabeto?

82

¿Cuál es la mejor implementación de Python pura para verificar si una cadena contiene CUALQUIER letra del alfabeto?

string_1 = "(555).555-5555"
string_2 = "(555) 555 - 5555 ext. 5555

Donde string_1volvería Falsepor no tener letras del alfabeto en él y string_2volvería Truepor tener letra.

Justin Papez
fuente
2
¿Debería limitarse solo al alfabeto inglés a / z? ¿Deben tenerse en cuenta los caracteres "especiales" de otros alfabetos, como el alemán?
Kotch
¿Existe alguna posibilidad de que reciba unicode? ¿O simplemente letras romanas ascii?
KobeJohn
Buen momento :) De todos modos, consulte esta pregunta similar si necesita ayuda para probar cadenas con caracteres Unicode.
KobeJohn
1
Limitado solo al alfabeto inglés a / z y solo letras romanas ascii simples :)
Justin Papez

Respuestas:

123

Regex debería ser un enfoque rápido:

re.search('[a-zA-Z]', the_string)
JBernardo
fuente
1
Gracias JBernado, esto es lo que terminé haciendo y funciona perfectamente para lo que necesito hacer.
Justin Papez
30
Regex ciertamente parece un poco exagerado. any(c.isalpha() for c in string_1)es deliciosamente Pythonic.
Jollywatt
5
@Joseph No, no lo es. Esta expresión regular es mucho más legible que su expresión. Además, ¿qué significa isalphaincluso? Esto tendrá comportamientos totalmente diferentes al comparar Python 2 con Python 3. ¿Es el chino parte del alfabeto? Si no es así, lo está haciendo coincidir ciegamente con su generador en Python 3 (¡O Python 2 para cadenas Unicode!). Si quieres Pythonic , aquí está: Simple is better than complex.. Y revise el comentario de OP arriba: Él quiere que solo se combine el alfabeto romano.
JBernardo
1
Creo que la respuesta de Joseph es perfectamente legible y ciertamente es más rápida que una importación adicional; además, no tiene que recordar el orden de los argumentos en re.search
Hinton
11
En caso de que alguien más se pregunte cuál es el valor de retorno, obtienes un Matchobjeto si hay una coincidencia o Nonesi no la hay. Entonces esto es compatible con un if re.search(...patrón.
Srini
74

Qué tal si:

>>> string_1 = "(555).555-5555"
>>> string_2 = "(555) 555 - 5555 ext. 5555"
>>> any(c.isalpha() for c in string_1)
False
>>> any(c.isalpha() for c in string_2)
True
DSM
fuente
¿ set(string_1)Sería más eficaz?
Rik Poggi
1
@Rik. ¿Te refieres a convertir string_1 en un conjunto antes de probarlo? No, no será más eficiente. Eso está garantizado para tratar con todos los caracteres al menos una vez, mientras que creo que la función any hará un cortocircuito (se detendrá) cuando encuentre el primer falso.
KobeJohn
Este código será algo lento porque requiere una llamada de función por carácter. La conversión a setpuede reducir o no las llamadas a funciones, pero agrega algunos gastos generales.
JBernardo
2
@JBernardo: timeit sugiere que se trata de un orden de magnitud más lento que una expresión regular compilada y solo toma aproximadamente un 66% más de tiempo que una no compilada. Eso está dentro de mis límites de "Odio las expresiones regulares".
DSM
1
Seguro: y si usa "(555) .555-5555 ext. 5555" * 1000, regresará a velocidades comparables debido al cortocircuito. Prefiero escribir en Python a escribir expresiones regulares, que encuentro difícil de depurar a menos que sean triviales, y no voy a dejar de escribir Python claro a menos que los requisitos de rendimiento lo exijan.
DSM
27

Puede usar islower()en su cadena para ver si contiene algunas letras minúsculas (entre otros caracteres). oresto conisupper() para comprobar también si contiene algunas letras mayúsculas:

abajo: letras en la cadena: la prueba arroja verdadero

>>> z = "(555) 555 - 5555 ext. 5555"
>>> z.isupper() or z.islower()
True

abajo: no hay letras en la cadena: la prueba arroja falso.

>>> z= "(555).555-5555"
>>> z.isupper() or z.islower()
False
>>> 

No confundirse con lo isalpha()que vuelveTrue solo si todos los caracteres son letras, que no es lo que quieres.

Tenga en cuenta que la respuesta de Barm completa la mía muy bien, ya que la mía no maneja bien el caso mixto.

Jean-François Fabre
fuente
3
Me gusta que esto probará si CONTIENE letras, no solo probar si la entrada es TODAS las letras.
Cornbeetle
@Cornbeetle sí, eso realmente responde la pregunta después de todos esos años, gracias
Jean-François Fabre
Muy buena forma de decirlo. ¿Cómo es en términos de eficiencia? mejor que regex?
pnv
no hay bucles de Python involucrados, por lo que la eficiencia es buena. No comparé con expresiones regulares, pero supongo que es un poco más rápido, especialmente para la fase de inicialización porque no hay expresiones regulares para compilar
Jean-François Fabre
13

Me gustó la respuesta proporcionada por @ jean-françois-fabre , pero está incompleta.
Su enfoque funcionará, pero solo si el texto contiene letras puramente minúsculas o mayúsculas:

>>> text = "(555).555-5555 extA. 5555"
>>> text.islower()
False
>>> text.isupper()
False

El mejor enfoque es poner primero en mayúsculas o minúsculas su cadena y luego verificar.

>>> string1 = "(555).555-5555 extA. 5555"
>>> string2 = '555 (234) - 123.32   21'

>>> string1.upper().isupper()
True
>>> string2.upper().isupper()
False
Levadura de cerveza
fuente
8

Puede usar expresiones regulares como esta:

import re

print re.search('[a-zA-Z]+',string)
astutamente
fuente
2

Probé cada uno de los métodos anteriores para encontrar si hay alfabetos contenidos en una cadena determinada y descubrí el tiempo de procesamiento promedio por cadena en una computadora estándar.

~ 250 ns para

import re

~ 3 µs para

re.search('[a-zA-Z]', string)

~ 6 µs para

any(c.isalpha() for c in string)

~ 850 ns para

string.upper().isupper()


Al contrario de lo que se alega, la importación de re toma un tiempo insignificante, y la búsqueda con re toma casi la mitad del tiempo en comparación con la iteración de isalpha () incluso para una cadena relativamente pequeña.
Por lo tanto, para cadenas y recuentos más grandes, re sería significativamente más eficiente.

Pero la conversión de la cadena a un caso y la comprobación del caso (es decir, cualquiera de las mayúsculas (). Isupper () o lower (). Islower () ) gana aquí. En cada bucle es significativamente más rápido que re.search () y ni siquiera requiere importaciones adicionales.

Mihir Verma
fuente
1
También puede compilar la expresión regular para una mayor optimización. alpha_regex = re.compile ('[a-zA-Z]') más tarde alpha_regex.search (string)
Behdad Forghani
Sin mencionar que isalpha () no funciona bien para varios idiomas. Estaba buscando esto porque quería verificar si una cadena que se espera que sea coreana contiene letras en inglés y el método isalpha () devuelve True para cada cadena coreana.
Chan Woo
0

También puedes hacer esto además

import re
string='24234ww'
val = re.search('[a-zA-Z]+',string) 
val[0].isalpha() # returns True if the variable is an alphabet
print(val[0]) # this will print the first instance of the matching value

También tenga en cuenta que si la variable val devuelve Ninguno. Eso significa que la búsqueda no encontró una coincidencia.

Ronald Saunfe
fuente