2010-04-14 20 views
10

En Perl Me gustaría hacer algo como esto para tomar diferentes campos en una expresión regular, separando los diferentes campos por() y conseguir que el uso de $Perl como expresiones regulares en Python

foreach $line (@lines) 
{ 
$line =~ m/(.*?):([^-]*)-(.*)/; 
    $field_1 = $1 
    $field_2 = $2 
    $field_3 = $3 
} 

¿Cómo podría hacer algo como esto en ¿Pitón?

Respuesta

8

Python admite expresiones regulares con el módulo re. El método re.search() devuelve un MatchObject que tiene métodos como group() que puede usar para recuperar la información del "grupo de captura".

Por ejemplo:

m = re.search(r'(.*?):([^-]*)-(.*)', line) 
field_1 = m.group(1) 
field_2 = m.group(2) 
field_3 = m.group(3) 
12

En Perl, que sería mucho mejor usar una gran variedad de sufijando un montón de escalares con los números. P.ej.

foreach my $line (@lines) { 
    my @matches = ($line =~ m/(.*?):([^-]*)-(.*)/); 
    ... 
} 

En Python, el módulo re devuelve un objeto partido que contiene la información de captura de grupo. Por lo que podría escribir:

match = re.search('(.*?):([^-]*)-(.*)', line) 

A continuación, sus partidos estarían disponibles en match.group(1), match.group(2), etc.

6

y no se olvide que en Python, TIMTOWTDI;)

import re 
p = re.compile(r'(\d+)\.(\d+)') 
num_parts = p.findall('11.22 333.444') # List of tuples. 
print num_parts       # [('11', '22'), ('333', '444')] 
+0

Creo que estás confundiendo con Python Perl; Simplemente lea 'import this' (es decir, The Zen of Python, o simplemente' python -c 'import this "| grep -i there') –

+0

@AleksiTorhamo ¿Tal vez está confundiendo la seriedad con una broma? ;) – FMc

+0

Ah, bien :-) Es solo que esta fue la segunda vez en un día que me encontré con alguien que decía eso, así que pensé que sería mejor que errar por el lado ingenuo/informativo :) (Y sí, yo ' Estoy bastante seguro de que el otro * tipo * hablaba en serio: D) –

18

"Canonical "Traducción de Python de su fragmento ...:

import re 

myre = re.compile(r'(.*?):([^-]*)-(.*)') 
for line in lines: 
    mo = myre.search(line) 
    field_1, field_2, field_3 = mo.groups() 

Importación re es obligatorio (las importaciones normalmente se realizan en la parte superior de un módulo, pero eso no es obligatorio). Precompilar el RE es opcional (si usa la función re.search en su lugar, compilará su patrón sobre la marcha) pero recomendado (para que no confíe en el caché del módulo de objetos RE compilados para su rendimiento, y también para tener un objeto RE y llame a sus métodos, que es más común en Python).

Puede usar el método match (que siempre trata de hacer coincidir desde el principio, si su patrón comienza con '^') o el método search (que intenta hacer coincidir en cualquier lugar); con su patrón dado, deberían ser equivalentes (pero no estoy 100% seguro).

El método .groups() devuelve todos los grupos coincidentes para que pueda asignarlos de un trago (usar una lista en Python, como usar una matriz en Perl, probablemente sería más normal, pero desde que eligió usar escalares en Perl puedes hacer el equivalente en Python también).

Esto fallará con una excepción si alguna línea no coincide con la RE, lo cual está bien si sabes que todas coinciden (no estoy seguro de cuál es el comportamiento de tu Perl, pero creo que podría "reutilizar" la los valores de la línea coincidente anterior en su lugar, lo cual es peculiar ... a menos que, de nuevo, sepa que todas las líneas coinciden ;-). Si desea acaba de saltar líneas no coincidentes, cambie la última declaración a los dos siguientes:

if mo: 
     field_1, field_2, field_3 = mo.groups() 
5

Así como un ejemplo alternativo, Python proporciona muy buen soporte para named capture groups (de hecho pitón apoyo pionera para los grupos de captura nombradas)

Para usar un grupo de captura con nombre, solo agregue ?P<the_name_of_the_group> dentro del paréntesis de apertura del grupo de captura.

Esto le permite obtener todos sus partidos en un diccionario muy fácilmente:

>>> import re 
>>> x = re.search("name: (?P<name>\w+) age: (?P<age>\d+)", "name: Bob age: 20") 
>>> x.groupdict() 
{'age': '20', 'name': 'Bob'} 

Aquí está el ejemplo de la OP, modificado para utilizar grupos de captura nombrados

import re 

find_fields_regex = re.compile(r'(?P<field1>.*?):(?P<field2>[^-]*)-(?P<field3>.*)') 
for line in lines: 
    search_result = find_fields_regex.search(line) 
    all_the_fields = search_result.groupdict() 

Ahora all_the_fields es un diccionario con claves correspondientes a los nombres de los grupos de captura ("campo1", "campo2" y "campo3") y los valores correspondientes a los contenidos de los respectivos grupos de captura.

¿Por qué se debe preferir nombrados grupos de captura

  • Con los grupos de captura con nombre, no importa si modifica el patrón de expresión para añadir más grupos de captura o eliminar grupos de captura existentes, todo lo que todavía se puso en el diccionario bajo las teclas correctas. Pero sin grupos de captura nombrados, debe verificar las asignaciones de variables cada vez que cambie la cantidad de grupos.
  • Los grupos de captura nombrados hacen que sus grupos de captura se autodescriban.
  • Puede seguir utilizando los números para referirse a los grupos si quieres:
>>> import re 
>>> x = re.search("name: (?P<name>\w+) age: (?P<age>\d+)", "name: Bob age: 20") 
>>> x.groupdict() 
{'age': '20', 'name': 'Bob'} 
>>> x.group(1) 
'Bob' 
>>> x.group(2) 
'20' 

Algunos buenos recursos de expresiones regulares:

Cuestiones relacionadas