2010-04-14 16 views
10

In Perl vorrei fare qualcosa di simile per prendere diversi campi in un'espressione regolare, che separa i campi diversi da() e far loro utilizzando $Perl come espressioni regolari in Python

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

Come potrei fare qualcosa di simile a Pitone?

risposta

8

Python supporta le espressioni regolari con il modulo re. Il metodo re.search() restituisce un MatchObject che ha metodi come group() che è possibile utilizzare per recuperare le informazioni sul "gruppo di cattura".

Ad esempio:

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

In Perl, si sarebbe molto meglio utilizzare un array di suffisso un mucchio di scalari con i numeri. Per esempio.

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

In Python, il modulo re restituisce un oggetto corrispondenza contenente le informazioni di cattura-gruppo. Così si potrebbe scrivere:

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

Poi le partite saranno disponibili in match.group(1), match.group(2), ecc

6

e non dimenticare che in 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

Credo che tu stia confondendo con Python Perl; Basta leggere 'import this' (ovvero, The Zen of Python, o semplicemente' python -c 'importare questo "| grep -i there') –

+0

@AleksiTorhamo Forse stai confondendo la serietà con uno scherzo? ;) – FMc

+0

Ah, bravo :-) E 'solo che questa è stata la seconda volta in un giorno in cui mi sono imbattuto in qualcuno che lo diceva, quindi ho pensato che sarebbe stato meglio errare dal lato ingenuo/informativo :) (E sì, io sono sicuro che l'altro * ragazzo fosse serio: D) –

18

"Canonical "Traduzione Python del tuo frammento ...:

import re 

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

Importazione re è un must (le importazioni vengono normalmente eseguite nella parte superiore di un modulo, ma non è obbligatorio). La precompilazione della RE è facoltativa (se invece usi la funzione re.search, essa compilerà il tuo modello al volo) ma ti consigliamo (quindi non fare affidamento sulla cache dei moduli degli oggetti RE compilati per le tue prestazioni, e anche per avere un oggetto RE e chiama i suoi metodi, che è più comune in Python).

È possibile utilizzare il metodo match (che tenta sempre la corrispondenza dall'inizio, indipendentemente dal fatto che il modello inizi o meno con '^') o il metodo search (che cerca la corrispondenza ovunque); con il tuo modello dato dovrebbero essere equivalenti (ma non sono sicuro al 100%).

Il metodo .groups() restituisce tutti i gruppi corrispondenti in modo da poterli assegnare tutti in un solo gulp (utilizzando un elenco in Python, proprio come utilizzare un array in Perl, sarebbe probabilmente più normale, ma poiché si è scelto di utilizzare gli scalari in Perl puoi fare l'equivalente anche in Python).

Questo fallirà con un'eccezione se qualsiasi riga non corrisponde alla RE, il che va bene se si sa che tutti corrispondono (non sono sicuro di quale sia il comportamento del Perl ma penso che "riutilizzerebbe" la i valori della riga di corrispondenza precedente, invece, che è particolare ... a meno che, ancora una volta tu sai che tutte le linee corrispondono ;-). Se si desidera saltare solo le linee che non corrispondono, modificare l'ultima istruzione per i due seguenti:

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

Proprio come un esempio alternativo, Python fornisce molto bello supporto per named capture groups (in realtà pitone sperimentato il supporto per gruppi di acquisizione denominati).

Per utilizzare un gruppo di acquisizione denominato, è sufficiente aggiungere ?P<the_name_of_the_group> all'interno della parentesi di apertura del gruppo di acquisizione.

Questo consente di ottenere tutte le partite in un dizionario molto facilmente:

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

Ecco l'esempio del PO, modificato per utilizzare i gruppi di cattura denominati

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() 

Ora all_the_fields è un dizionario con i tasti corrispondenti ai nomi dei gruppi di cattura ("campo1", "campo2" e "campo3") e i valori corrispondenti ai contenuti dei rispettivi gruppi di cattura.

Perché si dovrebbe preferire denominati gruppi di cattura

  • Con i gruppi di cattura con nome, non importa se si modifica il modello di espressione regolare per aggiungere più gruppi di cattura o rimuovere gruppi di cattura esistenti, tutto ciò che viene comunque messo nel dizionario sotto le chiavi corrette. Tuttavia, senza i gruppi di cattura denominati, è necessario ricontrollare gli assegnamenti delle variabili ogni volta che cambia il numero di gruppi.
  • I gruppi di acquisizione con nome rendono i gruppi di acquisizione autodocumentanti.
  • È comunque possibile utilizzare i numeri per riferirsi ai gruppi se si desidera:
>>> 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' 

Alcune buone risorse regex: