sub pattern online ignorecase example ejemplos python regex

pattern - re.sub python ejemplos



¿Vale la pena usar re.compile de Python? (22)

¿Hay algún beneficio en el uso de compilar para expresiones regulares en Python?

h = re.compile(''hello'') h.match(''hello world'')

vs

re.match(''hello'', ''hello world'')


Tengo mucha experiencia ejecutando una expresión regular compilada miles de veces en lugar de compilar sobre la marcha, y no he notado ninguna diferencia perceptible

Los votos sobre la respuesta aceptada llevan a suponer que lo que dice @Triptych es cierto para todos los casos. Esto no necesariamente es cierto. Una gran diferencia es cuando tienes que decidir si aceptar una cadena de expresiones regulares o un objeto de expresiones regulares compilado como un parámetro para una función:

>>> timeit.timeit(setup=""" ... import re ... f=lambda x, y: x.match(y) # accepts compiled regex as parameter ... h=re.compile(''hello'') ... """, stmt="f(h, ''hello world'')") 0.32881879806518555 >>> timeit.timeit(setup=""" ... import re ... f=lambda x, y: re.compile(x).match(y) # compiles when called ... """, stmt="f(''hello'', ''hello world'')") 0.809190034866333

Siempre es mejor compilar sus expresiones regulares en caso de que necesite reutilizarlos.

Tenga en cuenta que el ejemplo en el tiempo anterior simula la creación de un objeto de expresión regular compilado una vez en el momento de la importación en lugar de "sobre la marcha" cuando se requiere para una coincidencia.


Acabo de intentar esto yo mismo. Para el caso simple de analizar un número de una cadena y sumarlo, usar un objeto de expresión regular compilado es casi el doble de rápido que usar los métodos re .

Como han señalado otros, los métodos re (incluido re.compile ) buscan la cadena de expresión regular en un caché de expresiones compiladas previamente. Por lo tanto, en el caso normal, el costo adicional de usar los métodos re es simplemente el costo de la búsqueda de caché.

Sin embargo, el examen del code muestra que el caché está limitado a 100 expresiones. Esto plantea la pregunta, ¿qué tan doloroso es desbordar el caché? El código contiene una interfaz interna para el compilador de expresiones regulares, re.sre_compile.compile . Si lo llamamos, saltamos el caché. Resulta aproximadamente dos órdenes de magnitud más lento que una expresión regular básica, como r''/w+/s+([0-9_]+)/s+/w*'' .

Aquí está mi prueba:

#!/usr/bin/env python import re import time def timed(func): def wrapper(*args): t = time.time() result = func(*args) t = time.time() - t print ''%s took %.3f seconds.'' % (func.func_name, t) return result return wrapper regularExpression = r''/w+/s+([0-9_]+)/s+/w*'' testString = "average 2 never" @timed def noncompiled(): a = 0 for x in xrange(1000000): m = re.match(regularExpression, testString) a += int(m.group(1)) return a @timed def compiled(): a = 0 rgx = re.compile(regularExpression) for x in xrange(1000000): m = rgx.match(testString) a += int(m.group(1)) return a @timed def reallyCompiled(): a = 0 rgx = re.sre_compile.compile(regularExpression) for x in xrange(1000000): m = rgx.match(testString) a += int(m.group(1)) return a @timed def compiledInLoop(): a = 0 for x in xrange(1000000): rgx = re.compile(regularExpression) m = rgx.match(testString) a += int(m.group(1)) return a @timed def reallyCompiledInLoop(): a = 0 for x in xrange(10000): rgx = re.sre_compile.compile(regularExpression) m = rgx.match(testString) a += int(m.group(1)) return a r1 = noncompiled() r2 = compiled() r3 = reallyCompiled() r4 = compiledInLoop() r5 = reallyCompiledInLoop() print "r1 = ", r1 print "r2 = ", r2 print "r3 = ", r3 print "r4 = ", r4 print "r5 = ", r5 </pre> And here is the output on my machine: <pre> $ regexTest.py noncompiled took 4.555 seconds. compiled took 2.323 seconds. reallyCompiled took 2.325 seconds. compiledInLoop took 4.620 seconds. reallyCompiledInLoop took 4.074 seconds. r1 = 2000000 r2 = 2000000 r3 = 2000000 r4 = 2000000 r5 = 20000

Los métodos ''realmente compilados'' usan la interfaz interna, que omite la memoria caché. Tenga en cuenta que el que se compila en cada iteración de bucle solo se itera 10.000 veces, no un millón.


Además de la actuación.

El uso de compile me ayuda a distinguir los conceptos de
1. módulo (re) ,
2. objeto regex
3. hacer coincidir el objeto
Cuando empecé a aprender regex

#regex object regex_object = re.compile(r''[a-zA-Z]+'') #match object match_object = regex_object.search(''1.Hello'') #matching content match_object.group() output: Out[60]: ''Hello'' V.S. re.search(r''[a-zA-Z]+'',''1.Hello'').group() Out[61]: ''Hello''

Como complemento, hice una hoja de trucos exhaustiva del módulo para su referencia.

regex = { ''brackets'':{''single_character'': [''[]'', ''.'', {''negate'':''^''}], ''capturing_group'' : [''()'',''(?:)'', ''(?!)'' ''|'', ''//', ''backreferences and named group''], ''repetition'' : [''{}'', ''*?'', ''+?'', ''??'', ''greedy v.s. lazy ?'']}, ''lookaround'' :{''lookahead'' : [''(?=...)'', ''(?!...)''], ''lookbehind'' : [''(?<=...)'',''(?<!...)''], ''caputuring'' : [''(?P<name>...)'', ''(?P=name)'', ''(?:)''],}, ''escapes'':{''anchor'' : [''^'', ''/b'', ''$''], ''non_printable'' : [''/n'', ''/t'', ''/r'', ''/f'', ''/v''], ''shorthand'' : [''/d'', ''/w'', ''/s'']}, ''methods'': {[''search'', ''match'', ''findall'', ''finditer''], [''split'', ''sub'']}, ''match_object'': [''group'',''groups'', ''groupdict'',''start'', ''end'', ''span'',] }


Aquí hay un caso de prueba simple:

~$ for x in 1 10 100 1000 10000 100000 1000000; do python -m timeit -n $x -s ''import re'' ''re.match("[0-9]{3}-[0-9]{3}-[0-9]{4}", "123-123-1234")''; done 1 loops, best of 3: 3.1 usec per loop 10 loops, best of 3: 2.41 usec per loop 100 loops, best of 3: 2.24 usec per loop 1000 loops, best of 3: 2.21 usec per loop 10000 loops, best of 3: 2.23 usec per loop 100000 loops, best of 3: 2.24 usec per loop 1000000 loops, best of 3: 2.31 usec per loop

con re.compile:

~$ for x in 1 10 100 1000 10000 100000 1000000; do python -m timeit -n $x -s ''import re'' ''r = re.compile("[0-9]{3}-[0-9]{3}-[0-9]{4}")'' ''r.match("123-123-1234")''; done 1 loops, best of 3: 1.91 usec per loop 10 loops, best of 3: 0.691 usec per loop 100 loops, best of 3: 0.701 usec per loop 1000 loops, best of 3: 0.684 usec per loop 10000 loops, best of 3: 0.682 usec per loop 100000 loops, best of 3: 0.694 usec per loop 1000000 loops, best of 3: 0.702 usec per loop

Por lo tanto, parece que la compilación es más rápida con este caso simple, incluso si solo haces coincidencias una vez .


Corrí esta prueba antes de encontrar la discusión aquí. Sin embargo, habiéndolo ejecutado, pensé que al menos publicaría mis resultados.

Robé y bastardé el ejemplo en "Mastering Regular Expressions" de Jeff Friedl. Esto es en un macbook con OSX 10.6 (2GHz intel core 2 duo, 4GB de RAM). La versión de Python es 2.6.1.

Ejecutar 1 - usando re.compile

import re import time import fpformat Regex1 = re.compile(''^(a|b|c|d|e|f|g)+$'') Regex2 = re.compile(''^[a-g]+$'') TimesToDo = 1000 TestString = "" for i in range(1000): TestString += "abababdedfg" StartTime = time.time() for i in range(TimesToDo): Regex1.search(TestString) Seconds = time.time() - StartTime print "Alternation takes " + fpformat.fix(Seconds,3) + " seconds" StartTime = time.time() for i in range(TimesToDo): Regex2.search(TestString) Seconds = time.time() - StartTime print "Character Class takes " + fpformat.fix(Seconds,3) + " seconds" Alternation takes 2.299 seconds Character Class takes 0.107 seconds

Ejecutar 2 - No usar re.compile

import re import time import fpformat TimesToDo = 1000 TestString = "" for i in range(1000): TestString += "abababdedfg" StartTime = time.time() for i in range(TimesToDo): re.search(''^(a|b|c|d|e|f|g)+$'',TestString) Seconds = time.time() - StartTime print "Alternation takes " + fpformat.fix(Seconds,3) + " seconds" StartTime = time.time() for i in range(TimesToDo): re.search(''^[a-g]+$'',TestString) Seconds = time.time() - StartTime print "Character Class takes " + fpformat.fix(Seconds,3) + " seconds" Alternation takes 2.508 seconds Character Class takes 0.109 seconds


Curiosamente, la compilación es más eficiente para mí (Python 2.5.2 en Win XP):

import re import time rgx = re.compile(''(/w+)/s+[0-9_]?/s+/w*'') str = "average 2 never" a = 0 t = time.time() for i in xrange(1000000): if re.match(''(/w+)/s+[0-9_]?/s+/w*'', str): #~ if rgx.match(str): a += 1 print time.time() - t

Ejecutando el código anterior una vez como está, y una vez con las dos if líneas comentaron al revés, la expresión regular compilada es el doble de rápida


Dejando a un lado la diferencia de rendimiento, el uso de re.compile y el objeto compilado de expresiones regulares para hacer coincidir (independientemente de las operaciones relacionadas con expresiones regulares) hace que la semántica sea más clara respecto del tiempo de ejecución de Python.

Tuve una experiencia dolorosa de depurar un código simple:

compare = lambda s, p: re.match(p, s)

y luego usaría comparar en

[x for x in data if compare(patternPhrases, x[columnIndex])]

donde se supone que patternPhrases es una variable que contiene una cadena de expresión regular, x[columnIndex] es una variable que contiene una cadena.

¡Tuve problemas para que las patternPhrases no coincidieran con alguna cadena esperada!

Pero si uso el formulario re.compile:

compare = lambda s, p: p.match(s)

entonces en

[x for x in data if compare(patternPhrases, x[columnIndex])]

Python se habría quejado de que "la cadena no tiene un atributo de coincidencia", como por el mapeo de argumentos posicionales en compare , ¡ x[columnIndex] se usa como expresión regular !, cuando en realidad quise decir

compare = lambda p, s: p.match(s)

En mi caso, el uso de re.compile es más explícito del propósito de la expresión regular, cuando su valor está oculto a simple vista, por lo que podría obtener más ayuda de la verificación en tiempo de ejecución de Python.

Entonces, la moraleja de mi lección es que cuando la expresión regular no es solo una cadena literal, entonces debería usar re.compile para que Python me ayude a afirmar mi suposición.


En general, me parece que es más fácil usar banderas (al menos más fácil de recordar cómo), como re.I al compilar patrones que usar banderas en línea.

>>> foo_pat = re.compile(''foo'',re.I) >>> foo_pat.findall(''some string FoO bar'') [''FoO'']

vs

>>> re.findall(''(?i)foo'',''some string FoO bar'') [''FoO'']


Esta es una buena pregunta. A menudo ves que la gente usa re.compile sin razón. Disminuye la legibilidad. Pero seguro que hay muchas veces en que se requiere la precompilación de la expresión. Como cuando lo usas repetidas veces en un bucle o algo así.

Es como todo sobre la programación (todo en la vida en realidad). Aplicar el sentido común.


Esta respuesta puede llegar tarde pero es un hallazgo interesante. Usar compilación puede realmente ahorrarle tiempo si planea usar la expresión regular varias veces (esto también se menciona en los documentos). A continuación puede ver que el uso de un regex compilado es más rápido cuando se llama directamente al método de coincidencia. pasar una expresión regular compilada a re.match la hace aún más lenta y pasar re.match con la cadena de patrones está en algún lugar en el medio.

>>> ipr = r''/D+((([0-2][0-5]?[0-5]?)/.){3}([0-2][0-5]?[0-5]?))/D+'' >>> average(*timeit.repeat("re.match(ipr, ''abcd100.10.255.255 '')", globals={''ipr'': ipr, ''re'': re})) 1.5077415757028423 >>> ipr = re.compile(ipr) >>> average(*timeit.repeat("re.match(ipr, ''abcd100.10.255.255 '')", globals={''ipr'': ipr, ''re'': re})) 1.8324008992184038 >>> average(*timeit.repeat("ipr.match(''abcd100.10.255.255 '')", globals={''ipr'': ipr, ''re'': re})) 0.9187896518778871


Estoy de acuerdo con Honest Abe en que la match(...) en los ejemplos dados es diferente. No son comparaciones de uno a uno y, por lo tanto, los resultados varían. Para simplificar mi respuesta, uso A, B, C, D para esas funciones en cuestión. Oh sí, estamos tratando con 4 funciones en re.py en lugar de 3.

Ejecutando esta pieza de código:

h = re.compile(''hello'') # (A) h.match(''hello world'') # (B)

es lo mismo que ejecutar este código:

re.match(''hello'', ''hello world'') # (C)

Porque, cuando se mira en la fuente re.py , (A + B) significa:

h = re._compile(''hello'') # (D) h.match(''hello world'')

y (C) es en realidad:

re._compile(''hello'').match(''hello world'')

Entonces, (C) no es lo mismo que (B). De hecho, (C) llama (B) después de llamar (D), que también es llamada por (A). En otras palabras, (C) = (A) + (B) . Por lo tanto, comparar (A + B) dentro de un bucle tiene el mismo resultado que (C) dentro de un bucle.

La regexTest.py de regexTest.py de George demostró esto para nosotros.

noncompiled took 4.555 seconds. # (C) in a loop compiledInLoop took 4.620 seconds. # (A + B) in a loop compiled took 2.323 seconds. # (A) once + (B) in a loop

El interés de todos es cómo obtener el resultado de 2.323 segundos. Para asegurarnos de que compile(...) solo sea llamado una vez, necesitamos almacenar el objeto regex compilado en la memoria. Si estamos utilizando una clase, podríamos almacenar el objeto y reutilizarlo cada vez que se llame a nuestra función.

class Foo: regex = re.compile(''hello'') def my_function(text) return regex.match(text)

Si no estamos utilizando la clase (que es mi solicitud de hoy), entonces no tengo ningún comentario. Todavía estoy aprendiendo a usar la variable global en Python, y sé que la variable global es algo malo.

Un punto más, creo que el uso de (A) + (B) tiene una ventaja. Aquí hay algunos datos que observé (corríjame si me equivoco):

  1. Llamadas A una vez, hará una búsqueda en el _cache seguido de una sre_compile.compile() para crear un objeto de expresión regular. Llamadas A dos veces, hará dos búsquedas y una compilación (porque el objeto regex está en caché).

  2. Si el _cache se vacía, el objeto de expresión regular se libera de la memoria y Python necesita compilar nuevamente. (Alguien sugiere que Python no compilará).

  3. Si mantenemos el objeto de expresión regular utilizando (A), el objeto de expresión regular seguirá ingresando en _cache y se vaciará de alguna manera. Pero nuestro código mantiene una referencia en él y el objeto regex no se liberará de la memoria. Esos, Python no necesitan compilar de nuevo.

  4. Las diferencias de 2 segundos en la prueba de George compiledInLoop vs compiled es principalmente el tiempo requerido para construir la clave y buscar el _cache. No significa el tiempo de compilación de expresiones regulares.

  5. La prueba de realmente compilación de George muestra qué sucede si realmente vuelve a hacer la compilación cada vez: será 100 veces más lenta (redujo el bucle de 1.000.000 a 10.000).

Aquí están los únicos casos que (A + B) es mejor que (C):

  1. Si podemos almacenar en caché una referencia del objeto regex dentro de una clase.
  2. Si necesitamos llamar a (B) repetidamente (dentro de un bucle o varias veces), debemos almacenar en caché la referencia al objeto regex fuera del bucle.

Caso que (C) es suficientemente bueno:

  1. No podemos cachear una referencia.
  2. Solo lo usamos de vez en cuando.
  3. En general, no tenemos demasiadas expresiones regulares (supongamos que el compilado nunca se enjuaga)

Solo un resumen, aquí está el ABC:

h = re.compile(''hello'') # (A) h.match(''hello world'') # (B) re.match(''hello'', ''hello world'') # (C)

Gracias por leer.


FWIW:

$ python -m timeit -s "import re" "re.match(''hello'', ''hello world'')" 100000 loops, best of 3: 3.82 usec per loop $ python -m timeit -s "import re; h=re.compile(''hello'')" "h.match(''hello world'')" 1000000 loops, best of 3: 1.26 usec per loop

Por lo tanto, si va a utilizar mucho la misma expresión regular, puede valer la pena hacer re.compile (especialmente para expresiones regulares más complejas).

Se aplican los argumentos estándar contra la optimización prematura, pero no creo que pierda mucha claridad / re.compile usar re.compile si sospecha que sus expresiones regulares pueden convertirse en un cuello de botella en el rendimiento.

Actualizar:

Bajo Python 3.6 (sospecho que los tiempos anteriores se realizaron con Python 2.x) y el hardware 2018 (MacBook Pro), ahora obtengo los siguientes tiempos:

% python -m timeit -s "import re" "re.match(''hello'', ''hello world'')" 1000000 loops, best of 3: 0.661 usec per loop % python -m timeit -s "import re; h=re.compile(''hello'')" "h.match(''hello world'')" 1000000 loops, best of 3: 0.285 usec per loop % python -m timeit -s "import re" "h=re.compile(''hello''); h.match(''hello world'')" 1000000 loops, best of 3: 0.65 usec per loop % python --version Python 3.6.5 :: Anaconda, Inc.

También agregué un caso (observe las diferencias de comillas entre las dos últimas ejecuciones) que muestra que re.match(x, ...) es literalmente [aproximadamente] equivalente a re.compile(x).match(...) , es decir, no parece ocurrir ningún almacenamiento en caché entre bastidores de la representación compilada.


Hay una ventaja adicional de usar re.compile (), en la forma de agregar comentarios a mis patrones de expresiones regulares usando re.VERBOSE

pattern = '''''' hello[ ]world # Some info on my pattern logic. [ ] to recognize space '''''' re.search(pattern, ''hello world'', re.VERBOSE)

Aunque esto no afecta la velocidad de ejecución de su código, me gusta hacerlo de esta manera, ya que es parte de mi hábito de comentar. No me gusta pasar el tiempo tratando de recordar la lógica que quedó detrás de mi código 2 meses después cuando quiero hacer modificaciones.


He tenido mucha experiencia ejecutando una expresión regular compilada miles de veces en lugar de compilar sobre la marcha, y no he notado ninguna diferencia perceptible. Obviamente, esto es anecdótico, y ciertamente no es un gran argumento en contra de la compilación, pero he encontrado que la diferencia es insignificante.

EDITAR: Después de echar un vistazo rápido al código real de la biblioteca de Python 2.5, veo que Python compila internamente AND CACHES regexes cada vez que los usa (incluidas las llamadas a re.match() ), por lo que solo está cambiando CUANDO el regex obtiene compilado, y no debería ahorrar mucho tiempo en absoluto, solo el tiempo que lleva comprobar el caché (una búsqueda clave en un tipo de dict interno).

Desde el módulo re.py (los comentarios son míos):

def match(pattern, string, flags=0): return _compile(pattern, flags).match(string) def _compile(*key): # Does cache check at top of function cachekey = (type(key[0]),) + key p = _cache.get(cachekey) if p is not None: return p # ... # Does actual compilation on cache miss # ... # Caches compiled regex if len(_cache) >= _MAXCACHE: _cache.clear() _cache[cachekey] = p return p

Sigo compilando con frecuencia expresiones regulares, pero solo para vincularlas a un nombre agradable y reutilizable, no para ninguna ganancia de rendimiento esperada.


Para mí, el mayor beneficio de re.compile no es ningún tipo de optimización prematura (que es la raíz de todo mal , de anyway ). Es poder separar la definición de la expresión regular de su uso.

Incluso una expresión simple como 0|[1-9][0-9]* (entero en la base 10 sin ceros iniciales) puede ser lo suficientemente compleja como para que no tenga que volver a escribirla, verifique si realizó algún error tipográfico, y luego tendrá que volver a verificar si hay errores tipográficos al iniciar la depuración. Además, es mejor usar un nombre de variable como num o num_b10 que 0|[1-9][0-9]* .

Ciertamente es posible almacenar cadenas y pasarlas a re.match; Sin embargo, eso es menos legible:

num = "..." # then, much later: m = re.match(num, input)

Versus compilando:

num = re.compile("...") # then, much later: m = num.match(input)

Aunque está bastante cerca, la última línea de la segunda se siente más natural y más simple cuando se usa repetidamente.


Sobre todo, hay poca diferencia si usas re.compile o no. Internamente, todas las funciones se implementan en términos de un paso de compilación:

def match(pattern, string, flags=0): return _compile(pattern, flags).match(string) def fullmatch(pattern, string, flags=0): return _compile(pattern, flags).fullmatch(string) def search(pattern, string, flags=0): return _compile(pattern, flags).search(string) def sub(pattern, repl, string, count=0, flags=0): return _compile(pattern, flags).sub(repl, string, count) def subn(pattern, repl, string, count=0, flags=0): return _compile(pattern, flags).subn(repl, string, count) def split(pattern, string, maxsplit=0, flags=0): return _compile(pattern, flags).split(string, maxsplit) def findall(pattern, string, flags=0): return _compile(pattern, flags).findall(string) def finditer(pattern, string, flags=0): return _compile(pattern, flags).finditer(string)

Además, re.compile () omite la lógica adicional de indirección y almacenamiento en caché:

_cache = {} _pattern_type = type(sre_compile.compile("", 0)) _MAXCACHE = 512 def _compile(pattern, flags): # internal: compile pattern try: p, loc = _cache[type(pattern), pattern, flags] if loc is None or loc == _locale.setlocale(_locale.LC_CTYPE): return p except KeyError: pass if isinstance(pattern, _pattern_type): if flags: raise ValueError( "cannot process flags argument with a compiled pattern") return pattern if not sre_compile.isstring(pattern): raise TypeError("first argument must be string or compiled pattern") p = sre_compile.compile(pattern, flags) if not (flags & DEBUG): if len(_cache) >= _MAXCACHE: _cache.clear() if p.flags & LOCALE: if not _locale: return p loc = _locale.setlocale(_locale.LC_CTYPE) else: loc = None _cache[type(pattern), pattern, flags] = p, loc return p

Además del pequeño beneficio de la velocidad del uso de re.compile , a las personas también les gusta la legibilidad que se obtiene al nombrar especificaciones de patrones potencialmente complejos y separarlas de la lógica de negocios donde se aplican:

#### Patterns ############################################################ number_pattern = re.compile(r''/d+(/./d*)?'') # Integer or decimal number assign_pattern = re.compile(r'':='') # Assignment operator identifier_pattern = re.compile(r''[A-Za-z]+'') # Identifiers whitespace_pattern = re.compile(r''[/t ]+'') # Spaces and tabs #### Applications ######################################################## if whitespace_pattern.match(s): business_logic_rule_1() if assign_pattern.match(s): business_logic_rule_2()

Tenga en cuenta que otro encuestado creyó incorrectamente que los archivos pyc almacenaban patrones compilados directamente; sin embargo, en realidad se reconstruyen cada vez que se carga el PYC:

>>> from dis import dis >>> with open(''tmp.pyc'', ''rb'') as f: f.read(8) dis(marshal.load(f)) 1 0 LOAD_CONST 0 (-1) 3 LOAD_CONST 1 (None) 6 IMPORT_NAME 0 (re) 9 STORE_NAME 0 (re) 3 12 LOAD_NAME 0 (re) 15 LOAD_ATTR 1 (compile) 18 LOAD_CONST 2 (''[aeiou]{2,5}'') 21 CALL_FUNCTION 1 24 STORE_NAME 2 (lc_vowels) 27 LOAD_CONST 1 (None) 30 RETURN_VALUE

El desmontaje anterior proviene del archivo PYC para un tmp.py contiene:

import re lc_vowels = re.compile(r''[aeiou]{2,5}'')


Usando los ejemplos dados:

h = re.compile(''hello'') h.match(''hello world'')

El método de coincidencia en el ejemplo anterior no es el mismo que se usa a continuación:

re.match(''hello'', ''hello world'')

re.compile() devuelve un objeto de expresión regular , lo que significa que h es un objeto regex.

El objeto regex tiene su propio método de match con los parámetros pos y endpos opcionales:

match

pos

El segundo parámetro opcional pos da un índice en la cadena donde se debe iniciar la búsqueda; su valor predeterminado es 0. Esto no es completamente equivalente a cortar la cadena; el carácter del patrón ''^'' coincide con el comienzo real de la cadena y en las posiciones justo después de una nueva línea, pero no necesariamente en el índice donde se inicia la búsqueda.

endpos

El parámetro opcional endpos limita la distancia a la que se buscará la cadena; será como si la cadena tuviera una longitud de caracteres de endpos , por lo que solo se buscará una coincidencia en los caracteres de pos a endpos - 1 . Si endpos es menor que pos , no se encontrará ninguna coincidencia; de lo contrario, si rx es un objeto de expresión regular compilado, rx.search(string, 0, 50) es equivalente a rx.search(string[:50], 0) .

Los métodos de búsqueda , búsqueda y búsqueda de objetos de expresiones regulares también admiten estos parámetros.

re.match(pattern, string, flags=0) no los admite como puede ver,
ni tampoco sus contrapartes de búsqueda , búsqueda y búsqueda .

Un objeto coincidente tiene atributos que complementan estos parámetros:

match.pos

El valor de pos que se pasó al método search () o match () de un objeto regex. Este es el índice en la cadena en la que el motor RE comenzó a buscar una coincidencia.

match.endpos

El valor de endpos que se pasó al método search () o match () de un objeto regex. Este es el índice en la cadena más allá del cual el motor RE no irá.

Un objeto regex tiene dos atributos únicos, posiblemente útiles:

regex.groups

El número de grupos de captura en el patrón.

regex.groupindex

Un diccionario que mapea cualquier nombre de grupo simbólico definido por (? P) para agrupar números. El diccionario está vacío si no se usaron grupos simbólicos en el patrón.

Y finalmente, un objeto de coincidencia tiene este atributo:

match.re

El objeto de expresión regular cuyo método match () o search () produjo esta instancia de coincidencia.


(Meses después) es fácil agregar su propio caché alrededor de re.match, o cualquier otra cosa,

""" Re.py: Re.match = re.match + cache efficiency: re.py does this already (but what''s _MAXCACHE ?) readability, inline / separate: matter of taste """ import re cache = {} _re_type = type( re.compile( "" )) def match( pattern, str, *opt ): """ Re.match = re.match + cache re.compile( pattern ) """ if type(pattern) == _re_type: cpat = pattern elif pattern in cache: cpat = cache[pattern] else: cpat = cache[pattern] = re.compile( pattern, *opt ) return cpat.match( str ) # def search ...

Un wibni, ¿no sería bueno si: cachehint (size =), cacheinfo () -> size, hits, nclear ...


Las expresiones regulares se compilan antes de usarse cuando se usa la segunda versión. Si lo vas a ejecutar muchas veces, es mejor compilarlo primero. Si no está compilando, cada vez que coincida con uno está bien.


Me gustaría motivar que la precompilación es tanto conceptual como ''literalmente'' (como en ''programación alfabetizada'') una ventaja. Echa un vistazo a este fragmento de código:

from re import compile as _Re class TYPO: def text_has_foobar( self, text ): return self._text_has_foobar_re_search( text ) is not None _text_has_foobar_re_search = _Re( r"""(?i)foobar""" ).search TYPO = TYPO()

en tu aplicación, escribirías:

from TYPO import TYPO print( TYPO.text_has_foobar( ''FOObar ) )

Esto es casi tan simple en términos de funcionalidad como puede obtener. Debido a que este ejemplo es tan corto, combiné la manera de obtener _text_has_foobar_re_searchtodo en una línea. la desventaja de este código es que ocupa un poco de memoria por lo que sea la vida útil del TYPOobjeto de la biblioteca; La ventaja es que al hacer una búsqueda en foobar, saldrás con dos llamadas de función y dos búsquedas de diccionario de clase. la cantidad de expresiones regulares que se almacenan en caché rey la sobrecarga de esa memoria caché son irrelevantes aquí.

Compara esto con el estilo más habitual, a continuación:

import re class Typo: def text_has_foobar( self, text ): return re.compile( r"""(?i)foobar""" ).search( text ) is not None

En la aplicacion:

typo = Typo() print( typo.text_has_foobar( ''FOObar ) )

Admito fácilmente que mi estilo es muy inusual para python, tal vez incluso discutible. sin embargo, en el ejemplo que más se asemeja a cómo Python se usa principalmente, para hacer una única coincidencia, debemos instanciar un objeto, hacer tres búsquedas de diccionario de instancia y realizar tres llamadas de función; Además, podríamos tener reproblemas de almacenamiento en caché cuando usamos más de 100 expresiones regulares. Además, la expresión regular se oculta dentro del cuerpo del método, que la mayoría de las veces no es una buena idea.

se dice que cada subconjunto de medidas --- declaraciones de importación dirigidas y con alias; métodos de alias cuando sea aplicable; la reducción de llamadas a funciones y búsquedas de diccionarios de objetos puede ayudar a reducir la complejidad computacional y conceptual.


Realmente respeto todas las respuestas anteriores. De mi opinión ¡Sí! Por supuesto, vale la pena usar re.compile en lugar de compilar la expresión regular, una y otra vez, cada vez.

Usar re.compile hace que su código sea más dinámico, ya que puede llamar a la expresión regular ya compilada, en lugar de volver a compilar y volver a compilar. Esto te beneficia en los casos:

  1. Esfuerzos del procesador
  2. Complejidad del tiempo.
  3. Hace regex Universal (puede ser usado en findall, search, match)
  4. Y hace que tu programa se vea bien.

Ejemplo:

example_string = "The room number of her room is 26A7B." find_alpha_numeric_string = re.compile(r"/b/w+/b")

Usando en Findall

find_alpha_numeric_string.findall(example_string)

Usando en la búsqueda

find_alpha_numeric_string.search(example_string)

Del mismo modo puedes usarlo para: Match y Substitute


Tengo entendido que esos dos ejemplos son efectivamente equivalentes. La única diferencia es que en la primera, puede reutilizar la expresión regular compilada en otro lugar sin que se vuelva a compilar.

Aquí hay una referencia para usted: http://diveintopython3.ep.io/refactoring.html

Llamar a la función de búsqueda del objeto de patrón compilado con la cadena ''M'' logra lo mismo que llamar a re.search tanto con la expresión regular como con la cadena ''M''. Sólo mucho, mucho más rápido. (De hecho, la función re.search simplemente compila la expresión regular y llama el método de búsqueda del objeto del patrón resultante).