2012-05-02 11 views
8

Ho letto tutti i post correlati e ho perlustrato internet, ma questo mi sta veramente battendo.Come posso rendere meno avido lo sguardo negativo di Python?

Ho del testo contenente una data.
Vorrei acquisire la data, ma non se è preceduta da una determinata frase.

Una soluzione semplice è quella di aggiungere un aspetto negativo al mio RegEx.

Ecco alcuni esempi (utilizzando la ricerca).
Voglio solo catturare la data se non è preceduta dalla frase "as of".

19-2-11
qualcosa qualcosa 15-4-11
tali e quali di 29-5-11

Qui è la mia espressione regolare:

(?<!as of)(\d{1,2}-\d{1,2}-\d{2}) 

Risultati previsti:

['19 -2-11 ']
['15 -4-11']
[]

I risultati effettivi:

['19] -2-11'
['15 -4-11 ']
[' 9-5-11' ]

Si noti che è 9 non 29. Se cambio \d{1,2} a qualcosa di solido come \d{2} al primo modello :

bad regex for testing: (?<!as of)(\d{2}-\d{1,2}-\d{2}) 

Quindi ho ottenuto i risultati previsti. Ovviamente questo non va bene perché mi piacerebbe abbinare i giorni a 2 cifre così come i giorni a una cifra.

A quanto pare il mio aspetto negativo è avido di curiosità, più della mia acquisizione di data, quindi sta rubando una cifra da esso e in mancanza. Ho provato ogni mezzo per correggere l'avidità a cui riesco a pensare, ma non so proprio di aggiustarlo.

Vorrei che la mia acquisizione di data corrispondesse alla massima avidità, e quindi applicare la mia immagine negativa. È possibile? Il mio problema mi sembrava un buon uso di sguardi negativi e non eccessivamente complicato. Sono sicuro di poterlo realizzare in un altro modo, se devo, ma mi piacerebbe imparare come farlo.

Come posso rendere meno avido lo sguardo negativo di Python?

risposta

1

Il motivo non è perché lookbehind è avido. Ciò accade perché il motore regex tenta di far corrispondere il pattern in ogni posizione possibile.

Si avanza attraverso la frase such and such as of 29-5-11 inizialmente corrispondente a (?<!as of) all'inizio, ma non riesce a corrispondere a \d{1,2}.

Tuttavia, il motore si trova nella posizione such and such as of !29-5-11 (contrassegnato con !). Ma qui non riesce a eguagliare (?<!as of).

E passa alla posizione successiva: such and such as of 2!9-5-11. Dove corrisponde con successo a (?<!as of) e quindi a \d{1,2}.

Come evitarlo?

La soluzione generale è di formulare il modello il più chiaro possibile.

In questo caso inserirò la cifra con lo spazio necessario o l'inizio della stringa.

(?<!as of)(?:^|\s+)(\d{1,2}-\d{1,2}-\d{2}) 

La soluzione di Mark Byers è anche molto buona.

Penso che sia molto importante capire il motivo per cui il motore regex si comporta in questo modo e fornisce risultati indesiderati.

A proposito la soluzione che ho dato sopra non funziona se ci sono 2 o più spazi. Non funziona perché la posizione del pugno corrisponde a questo punto such and such as of ! 29-5-11 con il modello sopra menzionato.

Cosa si può fare per evitarlo?

Purtroppo il lookbehind nel motore regex di Python non supporta i quantificatori + o *.

Penso che la soluzione più semplice sarebbe quella di assicurarsi che non ci sia spazi prima (?:^|\s+) (meaing che tutti gli spazi vengono consumati da (?:^|\s+) subito dopo qualsiasi testo non-spazio (e nel caso in cui il testo è as of, terminano avanzando e tornate alla successiva posizione di partenza di iniziare la ricerca di nuovo alla prossima posizione del testo cercato).

re.search(r'(?<!as of)(?<!\s)(?:^|\s+)(\d{1,2}-\d{1,2}-\d{2})','such and such as of 29-5-11').group(1) 
+0

Questo è fantastico, trovo '(?:^| \ S +)' e la tua spiegazione è molto chiara. Sento la mia domanda ha una risposta.:) Puramente per motivi di conoscenza e non di necessità mi piacerebbe imparare come modificare questo in modo che '\ s' sia opzionale, tale che' qualcosa qualcosa da 15-4-11 'potrebbe corrispondere, ma potrei essere in grado di capire fuori me stesso. Grazie! –

+0

@ChristopherGalpin Penso che possa essere ottenuto molto facilmente usando '*' (da 0 a infinito occorrenze) invece di '+' (da 1 a infinito occorrenze) in questa parte del modello: '(?:^| \ S +) ' – ovgolovin

+0

Avevo sperato che fosse così facile ma evidentemente no, interrompe la partita' as of' nello stesso modo della domanda originale. –

7

Questo non ha nulla a che fare con l'avidità. L'avidità non cambia se un'espressione regolare corrisponde o meno - cambia solo l'ordine in cui viene eseguita la ricerca. Il problema qui è che la tua espressione regolare deve essere più specifica per evitare corrispondenze indesiderate.

Per risolvere il problema si potrebbe richiedere un confine di parola poco prima della partita:

(?<!as of)\b(\d{1,2}-\d{1,2}-\d{2}) 
#   ^^ add this 
+0

Beh, questo ha funzionato e ora mi sento stupido :) Grazie mille u! So che questo estende la domanda originale, ma esiste un modo semplice per assimilare spazi bianchi tra frase e data? Il lookbehind deve essere a larghezza fissa, quindi non può entrare, ma aggiungere \ s * vicino alla data sembra far risorgere il problema. –

+2

Che ne dici di questo: '(?

+0

Grazie, sto trovando questo molto educativo. –

-1

Una soluzione semplice sarebbe quella di buttare via tutte le linee che corrispondono a 'come della' prima di usare l'espressione regolare per isolare le date

+2

"Fred era il capo di ieri, al potere dal 31-12-11, ..." => FAIL –

Problemi correlati