Esta solución coincidirá con cadenas de longitud cero. use + en lugar de * para que coincida con cadenas de 1 o más caracteres.
Jerub
10
@Prestaul: \wincluye \dy _, por lo tanto isvalid = re.match(r'[\w-]+$', astr)o isinvalid = re.search(r'[^\w-]', astr). La posible presencia de locale.setlocalecadenas Unicode o de cadenas requiere una consideración adicional.
JFS
1
Corrección: isvalid = re.match(r'[\w-]*$', astr)- las cadenas vacías son válidas.
jfs
¿Cómo puede permitir también un punto / punto (.) En esa expresión regular? Editar, así es como: ^ [a-zA-Z0-9 -_ \ s \.] + $
fredrik
24
[Editar] Hay otra solución que aún no se menciona, y parece superar a las demás dadas hasta ahora en la mayoría de los casos.
Use string.translate para reemplazar todos los caracteres válidos en la cadena, y vea si nos quedan algunos inválidos. Esto es bastante rápido, ya que usa la función C subyacente para hacer el trabajo, con muy poco código de bytes de Python involucrado.
Obviamente, el rendimiento no lo es todo: buscar las soluciones más legibles es probablemente el mejor enfoque cuando no se encuentra en una ruta de código crítica para el rendimiento, pero solo para ver cómo se comparan las soluciones, aquí hay una comparación de rendimiento de todos los métodos propuestos hasta ahora. check_trans es el que usa el método string.translate.
Código de prueba:
import string, re, timeit
pat = re.compile('[\w-]*$')
pat_inv = re.compile ('[^\w-]')
allowed_chars=string.ascii_letters + string.digits + '_-'
allowed_set = set(allowed_chars)
trans_table = string.maketrans('','')
defcheck_set_diff(s):returnnot set(s) - allowed_set
defcheck_set_all(s):return all(x in allowed_set for x in s)
defcheck_set_subset(s):return set(s).issubset(allowed_set)
defcheck_re_match(s):return pat.match(s)
defcheck_re_inverse(s):# Search for non-matching character.returnnot pat_inv.search(s)
defcheck_trans(s):returnnot s.translate(trans_table,allowed_chars)
test_long_almost_valid='a_very_long_string_that_is_mostly_valid_except_for_last_char'*99 + '!'
test_long_valid='a_very_long_string_that_is_completely_valid_' * 99
test_short_valid='short_valid_string'
test_short_invalid='/$%$%&'
test_long_invalid='/$%$%&' * 99
test_empty=''defmain():
funcs = sorted(f for f in globals() if f.startswith('check_'))
tests = sorted(f for f in globals() if f.startswith('test_'))
for test in tests:
print"Test %-15s (length = %d):" % (test, len(globals()[test]))
for func in funcs:
print" %-20s : %.3f" % (func,
timeit.Timer('%s(%s)' % (func, test), 'from __main__ import pat,allowed_set,%s' % ','.join(funcs+tests)).timeit(10000))
printif __name__=='__main__': main()
El enfoque de traducción parece mejor en la mayoría de los casos, dramáticamente con cadenas largas válidas, pero es superado por expresiones regulares en test_long_invalid (presumiblemente porque la expresión regular puede rescatar inmediatamente, pero la traducción siempre tiene que escanear toda la cadena). Los enfoques establecidos suelen ser los peores, superando las expresiones regulares solo para el caso de cadenas vacías.
El uso de all (x en permitido_set para x en s) funciona bien si se rescata temprano, pero puede ser malo si tiene que iterar a través de cada carácter. isSubSet y set difference son comparables y son consistentemente proporcionales a la longitud de la cadena independientemente de los datos.
Existe una diferencia similar entre los métodos de expresiones regulares que coinciden con todos los caracteres válidos y la búsqueda de caracteres no válidos. La coincidencia funciona un poco mejor cuando se busca una cadena larga pero completamente válida, pero peor para los caracteres no válidos cerca del final de la cadena.
Úselo en string.ascii_letterslugar de string.letterssi no usa el indicador re.LOCALE para las expresiones regulares (de lo contrario, podría obtener resultados falsos positivos check_trans(). string.maketrans()No funcionará para cadenas Unicode.)
jfs
Para Python 3 / Unicode / from __future__ import unicode_literals), use trans_table3 = dict((ord(char), '') for char in allowed_chars)y def check_trans(s): return not s.translate(trans_table3). Pero, en general, funciona peor que las versiones RE.
Hugo
14
Hay una variedad de formas de lograr este objetivo, algunas son más claras que otras. Para cada uno de mis ejemplos, 'Verdadero' significa que la cadena pasada es válida, 'Falso' significa que contiene caracteres no válidos.
En primer lugar, está el enfoque ingenuo:
import string
allowed = string.letters + string.digits + '_' + '-'defcheck_naive(mystring):return all(c in allowed for c in mystring)
Luego está el uso de una expresión regular, puede hacer esto con re.match (). Tenga en cuenta que '-' debe estar al final de []; de lo contrario, se utilizará como delimitador de 'rango'. También tenga en cuenta el $ que significa 'final de cadena'. Otras respuestas indicadas en esta pregunta usan una clase de caracteres especial, '\ w', siempre prefiero usar un rango de clase de caracteres explícito usando [] porque es más fácil de entender sin tener que buscar una guía de referencia rápida, y más fácil de especial- caso.
import re
CHECK_RE = re.compile('[a-zA-Z0-9_-]+$')
defcheck_re(mystring):return CHECK_RE.match(mystring)
Otra solución señaló que puede hacer una coincidencia inversa con expresiones regulares, lo he incluido aquí ahora. Tenga en cuenta que [^ ...] invierte la clase de caracteres porque se usa ^:
También puedes hacer algo complicado con el objeto 'set'. Eche un vistazo a este ejemplo, que elimina de la cadena original todos los caracteres que están permitidos, dejándonos con un conjunto que contiene a) nada, ob) los caracteres ofensivos de la cadena:
En su primera prueba de expresiones regulares, "[a-zA-Z0-9 _-] + $" no debería ser "[a-zA-Z0-9 _-] * $". La cadena vacía probablemente debería considerarse coincidente.
Brian
Úselo string.ascii_letterssi usa expresiones regulares '[a-zA-Z]'.
jfs
12
Si no fuera por los guiones y guiones bajos, la solución más sencilla sería
my_little_string.isalnum()
(Sección 3.6.1 de la Referencia de la biblioteca de Python)
Como alternativa al uso de expresiones regulares, puede hacerlo en Conjuntos:
from sets import Set
allowed_chars = Set('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-')
if Set(my_little_sting).issubset(allowed_chars):
# your actionprintTrue
import re;
re.fullmatch("^[\w-]+$", target_string) # fullmatch looks also workable for python 3.4
\w: Solamente [a-zA-Z0-9_]
Por lo tanto, debe agregar -char para justificar el guión char.
+: Coincide con una o más repeticiones del carácter anterior. Supongo que no acepta entradas en blanco. Pero si lo hace, cambie a *.
^: Coincide con el inicio de la cadena.
$: Coincide con el final de la cadena.
Necesita estos dos caracteres especiales ya que debe evitar el siguiente caso. Los caracteres no deseados como &aquí pueden aparecer entre el patrón coincidente.
Bueno, puedes pedir la ayuda de regex, el genial aquí :)
código:
import re
string = 'adsfg34wrtwe4r2_()'#your string that needs to be matched.
regex = r'^[\w\d_()]*$'# you can also add a space in regex if u want to allow it in the string if re.match(regex,string):
print'yes'else:
print'false'
Siempre puede usar una lista de comprensión y verificar los resultados con todos, sería un poco menos intensivo en recursos que usar una expresión regular: all([c in string.letters + string.digits + ["_", "-"] for c in mystring])
Pruebe su código antes de publicarlo. Una solución basada en su respuesta rota que se ejecuta es: all (c en string.letters + string.digits + "_" para c en mystring)
Jerub
2
Eso requerirá muchos más recursos que una expresión regular. Está haciendo un escaneo lineal para cada personaje (mejor construir un conjunto con anticipación), y está construyendo innecesariamente una lista cuando la comprensión del generador sería más liviana.
Brian
-1
Aquí hay algo basado en el "enfoque ingenuo" de Jerub (¡ingenuo son sus palabras, no las mías!):
import string
ALLOWED = frozenset(string.ascii_letters + string.digits + '_' + '-')
defcheck(mystring):return all(c in ALLOWED for c in mystring)
Si ALLOWEDfuera una cadena, creo c in ALLOWEDque implicaría iterar sobre cada carácter de la cadena hasta que encuentre una coincidencia o llegue al final. Lo cual, para citar a Joel Spolsky, es una especie de algoritmo de Shlemiel the Painter .
Pero probar la existencia en un conjunto debería ser más eficiente, o al menos menos dependiente del número de caracteres permitidos. Ciertamente, este enfoque es un poco más rápido en mi máquina. Está claro y creo que funciona bastante bien en la mayoría de los casos (en mi máquina lenta puedo validar decenas de miles de cadenas cortas en una fracción de segundo). Me gusta.
REALMENTE en mi máquina, una expresión regular funciona varias veces más rápido, y es tan simple como esto (posiblemente más simple). Probablemente esa sea la mejor manera de avanzar.
Todos estos personajes deben estar en una clase, o obtendrás falsos negativos. Además, olvidó incluir los marcadores de comienzo y final de cadena ... así, siempre coincidirá siempre que haya un carácter válido.
Thomas
1
Esto realmente coincidirá incluso si no hay caracteres válidos. Coincidencia de longitud cero. Además, no está en Python.
Respuestas:
Una expresión regular funcionará con muy poco código:
import re ... if re.match("^[A-Za-z0-9_-]*$", my_little_string): # do something here
fuente
\w
incluye\d
y_
, por lo tantoisvalid = re.match(r'[\w-]+$', astr)
oisinvalid = re.search(r'[^\w-]', astr)
. La posible presencia delocale.setlocale
cadenas Unicode o de cadenas requiere una consideración adicional.isvalid = re.match(r'[\w-]*$', astr)
- las cadenas vacías son válidas.[Editar] Hay otra solución que aún no se menciona, y parece superar a las demás dadas hasta ahora en la mayoría de los casos.
Use string.translate para reemplazar todos los caracteres válidos en la cadena, y vea si nos quedan algunos inválidos. Esto es bastante rápido, ya que usa la función C subyacente para hacer el trabajo, con muy poco código de bytes de Python involucrado.
Obviamente, el rendimiento no lo es todo: buscar las soluciones más legibles es probablemente el mejor enfoque cuando no se encuentra en una ruta de código crítica para el rendimiento, pero solo para ver cómo se comparan las soluciones, aquí hay una comparación de rendimiento de todos los métodos propuestos hasta ahora. check_trans es el que usa el método string.translate.
Código de prueba:
import string, re, timeit pat = re.compile('[\w-]*$') pat_inv = re.compile ('[^\w-]') allowed_chars=string.ascii_letters + string.digits + '_-' allowed_set = set(allowed_chars) trans_table = string.maketrans('','') def check_set_diff(s): return not set(s) - allowed_set def check_set_all(s): return all(x in allowed_set for x in s) def check_set_subset(s): return set(s).issubset(allowed_set) def check_re_match(s): return pat.match(s) def check_re_inverse(s): # Search for non-matching character. return not pat_inv.search(s) def check_trans(s): return not s.translate(trans_table,allowed_chars) test_long_almost_valid='a_very_long_string_that_is_mostly_valid_except_for_last_char'*99 + '!' test_long_valid='a_very_long_string_that_is_completely_valid_' * 99 test_short_valid='short_valid_string' test_short_invalid='/$%$%&' test_long_invalid='/$%$%&' * 99 test_empty='' def main(): funcs = sorted(f for f in globals() if f.startswith('check_')) tests = sorted(f for f in globals() if f.startswith('test_')) for test in tests: print "Test %-15s (length = %d):" % (test, len(globals()[test])) for func in funcs: print " %-20s : %.3f" % (func, timeit.Timer('%s(%s)' % (func, test), 'from __main__ import pat,allowed_set,%s' % ','.join(funcs+tests)).timeit(10000)) print if __name__=='__main__': main()
Los resultados en mi sistema son:
Test test_empty (length = 0): check_re_inverse : 0.042 check_re_match : 0.030 check_set_all : 0.027 check_set_diff : 0.029 check_set_subset : 0.029 check_trans : 0.014 Test test_long_almost_valid (length = 5941): check_re_inverse : 2.690 check_re_match : 3.037 check_set_all : 18.860 check_set_diff : 2.905 check_set_subset : 2.903 check_trans : 0.182 Test test_long_invalid (length = 594): check_re_inverse : 0.017 check_re_match : 0.015 check_set_all : 0.044 check_set_diff : 0.311 check_set_subset : 0.308 check_trans : 0.034 Test test_long_valid (length = 4356): check_re_inverse : 1.890 check_re_match : 1.010 check_set_all : 14.411 check_set_diff : 2.101 check_set_subset : 2.333 check_trans : 0.140 Test test_short_invalid (length = 6): check_re_inverse : 0.017 check_re_match : 0.019 check_set_all : 0.044 check_set_diff : 0.032 check_set_subset : 0.037 check_trans : 0.015 Test test_short_valid (length = 18): check_re_inverse : 0.125 check_re_match : 0.066 check_set_all : 0.104 check_set_diff : 0.051 check_set_subset : 0.046 check_trans : 0.017
El enfoque de traducción parece mejor en la mayoría de los casos, dramáticamente con cadenas largas válidas, pero es superado por expresiones regulares en test_long_invalid (presumiblemente porque la expresión regular puede rescatar inmediatamente, pero la traducción siempre tiene que escanear toda la cadena). Los enfoques establecidos suelen ser los peores, superando las expresiones regulares solo para el caso de cadenas vacías.
El uso de all (x en permitido_set para x en s) funciona bien si se rescata temprano, pero puede ser malo si tiene que iterar a través de cada carácter. isSubSet y set difference son comparables y son consistentemente proporcionales a la longitud de la cadena independientemente de los datos.
Existe una diferencia similar entre los métodos de expresiones regulares que coinciden con todos los caracteres válidos y la búsqueda de caracteres no válidos. La coincidencia funciona un poco mejor cuando se busca una cadena larga pero completamente válida, pero peor para los caracteres no válidos cerca del final de la cadena.
fuente
string.ascii_letters
lugar destring.letters
si no usa el indicador re.LOCALE para las expresiones regulares (de lo contrario, podría obtener resultados falsos positivoscheck_trans()
.string.maketrans()
No funcionará para cadenas Unicode.)from __future__ import unicode_literals
), usetrans_table3 = dict((ord(char), '') for char in allowed_chars)
y defcheck_trans(s): return not s.translate(trans_table3)
. Pero, en general, funciona peor que las versiones RE.Hay una variedad de formas de lograr este objetivo, algunas son más claras que otras. Para cada uno de mis ejemplos, 'Verdadero' significa que la cadena pasada es válida, 'Falso' significa que contiene caracteres no válidos.
En primer lugar, está el enfoque ingenuo:
import string allowed = string.letters + string.digits + '_' + '-' def check_naive(mystring): return all(c in allowed for c in mystring)
Luego está el uso de una expresión regular, puede hacer esto con re.match (). Tenga en cuenta que '-' debe estar al final de []; de lo contrario, se utilizará como delimitador de 'rango'. También tenga en cuenta el $ que significa 'final de cadena'. Otras respuestas indicadas en esta pregunta usan una clase de caracteres especial, '\ w', siempre prefiero usar un rango de clase de caracteres explícito usando [] porque es más fácil de entender sin tener que buscar una guía de referencia rápida, y más fácil de especial- caso.
import re CHECK_RE = re.compile('[a-zA-Z0-9_-]+$') def check_re(mystring): return CHECK_RE.match(mystring)
Otra solución señaló que puede hacer una coincidencia inversa con expresiones regulares, lo he incluido aquí ahora. Tenga en cuenta que [^ ...] invierte la clase de caracteres porque se usa ^:
CHECK_INV_RE = re.compile('[^a-zA-Z0-9_-]') def check_inv_re(mystring): return not CHECK_INV_RE.search(mystring)
También puedes hacer algo complicado con el objeto 'set'. Eche un vistazo a este ejemplo, que elimina de la cadena original todos los caracteres que están permitidos, dejándonos con un conjunto que contiene a) nada, ob) los caracteres ofensivos de la cadena:
def check_set(mystring): return not set(mystring) - set(allowed)
fuente
string.ascii_letters
si usa expresiones regulares '[a-zA-Z]'.Si no fuera por los guiones y guiones bajos, la solución más sencilla sería
(Sección 3.6.1 de la Referencia de la biblioteca de Python)
fuente
Como alternativa al uso de expresiones regulares, puede hacerlo en Conjuntos:
from sets import Set allowed_chars = Set('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-') if Set(my_little_sting).issubset(allowed_chars): # your action print True
fuente
pat = re.compile ('[^\w-]') def onlyallowed(s): return not pat.search (s)
fuente
La expresión regular puede ser muy flexible.
import re; re.fullmatch("^[\w-]+$", target_string) # fullmatch looks also workable for python 3.4
\w
: Solamente[a-zA-Z0-9_]
Por lo tanto, debe agregar
-
char para justificar el guión char.+
: Coincide con una o más repeticiones del carácter anterior. Supongo que no acepta entradas en blanco. Pero si lo hace, cambie a*
.^
: Coincide con el inicio de la cadena.$
: Coincide con el final de la cadena.Necesita estos dos caracteres especiales ya que debe evitar el siguiente caso. Los caracteres no deseados como
&
aquí pueden aparecer entre el patrón coincidente.&&&PATTERN&&PATTERN
fuente
Bueno, puedes pedir la ayuda de regex, el genial aquí :)
código:
import re string = 'adsfg34wrtwe4r2_()' #your string that needs to be matched. regex = r'^[\w\d_()]*$' # you can also add a space in regex if u want to allow it in the string if re.match(regex,string): print 'yes' else: print 'false'
Salida:
Espero que esto ayude :)
fuente
Siempre puede usar una lista de comprensión y verificar los resultados con todos, sería un poco menos intensivo en recursos que usar una expresión regular:
all([c in string.letters + string.digits + ["_", "-"] for c in mystring])
fuente
Aquí hay algo basado en el "enfoque ingenuo" de Jerub (¡ingenuo son sus palabras, no las mías!):
import string ALLOWED = frozenset(string.ascii_letters + string.digits + '_' + '-') def check(mystring): return all(c in ALLOWED for c in mystring)
Si
ALLOWED
fuera una cadena, creoc in ALLOWED
que implicaría iterar sobre cada carácter de la cadena hasta que encuentre una coincidencia o llegue al final. Lo cual, para citar a Joel Spolsky, es una especie de algoritmo de Shlemiel the Painter .Pero probar la existencia en un conjunto debería ser más eficiente, o al menos menos dependiente del número de caracteres permitidos. Ciertamente, este enfoque es un poco más rápido en mi máquina. Está claro y creo que funciona bastante bien en la mayoría de los casos (en mi máquina lenta puedo validar decenas de miles de cadenas cortas en una fracción de segundo). Me gusta.
REALMENTE en mi máquina, una expresión regular funciona varias veces más rápido, y es tan simple como esto (posiblemente más simple). Probablemente esa sea la mejor manera de avanzar.
fuente
¡use una expresión regular y vea si coincide!
([a-z][A-Z][0-9]\_\-)*
fuente