2016-07-06 103 views
6

che sto cercando di fare quanto segue con un'espressione regolare:Python espressioni regolari per sostituire tutto, ma le parole specifiche

import re 
x = re.compile('[^(going)|^(you)]') # words to replace 
s = 'I am going home now, thank you.' # string to modify 
print re.sub(x, '_', s) 

Il risultato che ottengo è:

'_____going__o___no______n__you_' 

il risultato che voglio è:

'_____going_________________you_' 

Dal momento che l'^ può essere utilizzato solo tra parentesi [], questo risultato ha senso, ma non sono sicuro di come fare altrimenti.

Ho anche provato '([^g][^o][^i][^n][^g])|([^y][^o][^u])' ma produce '_g_h___y_'.

+1

Solo FYI: il motivo per cui il '[^ (going) |^(you)]' fallisce è perché la sintassi '[..]' produce una * sola corrispondenza di caratteri *. Il '' 'all'inizio è speciale, anzi significa 'non', ma ogni cosa dopo è considerata un set personalizzato di caratteri:'()^ginouy | '. – usr2564301

risposta

5

Non è così facile come appare prima, poiché non c'è "non" in RE eccetto ^ all'interno di [ ] che corrisponde solo a un carattere (come hai trovato). Qui è la mia soluzione:

import re 

def subit(m): 
    stuff, word = m.groups() 
    return ("_" * len(stuff)) + word 

s = 'I am going home now, thank you.' # string to modify 

print re.sub(r'(.+?)(going|you|$)', subit, s) 

Dà:

_____going_________________you_ 

da spiegare. Lo stesso RE (utilizzo sempre stringhe non elaborate) corrisponde a uno o più caratteri (.+) ma non è goloso (?). Questo viene catturato nel primo gruppo di parentesi (le parentesi). Ciò è seguito da "going" o "you" o dalla fine della riga ($).

subit è una funzione (è possibile chiamarla qualsiasi all'interno della ragione) che viene chiamata per ogni sostituzione. Viene passato un oggetto partita , dal quale è possibile recuperare i gruppi catturati. Il primo gruppo ci serve solo la lunghezza, dal momento che stiamo sostituendo ogni carattere con un trattino basso. La stringa restituita è sostituita da quella corrispondente al modello.

3

Qui è un approccio un espressione regolare:

>>> re.sub(r'(?!going|you)\b([\S\s]+?)(\b|$)', lambda x: (x.end() - x.start())*'_', s) 
'_____going_________________you_' 

L'idea è che quando hai a che fare con le parole e si desidera escludere loro o, ecc è necessario ricordare che la maggior parte dei motori regex (la maggior parte di li usano tradizionali NFA) analizzano le stringhe in base ai personaggi. E qui dato che vuoi escludere due parole e vuoi usare un lookahead negativo devi definire le stringhe consentite come parole (usando il limite di parole) e dato che in sub sostituisce i pattern abbinati con la sua stringa di sostituzione non puoi semplicemente passare il _ perché in tal caso sostituirà una parte come I am con 3 trattini bassi (I, '', 'am'). Quindi puoi usare una funzione per passare come secondo argomento di sub e moltiplicare lo _ con la lunghezza della stringa abbinata da sostituire.

+0

L'ultimo '.' prima della fine del testo? Inoltre, non abbastanza underscore tra 'going' e' you'. – cdarke

+0

@cdarke Sì, sembra così, fammi controllare! – Kasramvd

+1

@cdarke Puoi controllare la modifica ora ;-) – Kasramvd