regex per abbinare, ma sostituire solo una parte del pattern, in python
Tutti gli esempi che ho trovato sullo stack overflow sono troppo complicati per me da decodificare .
Considera questo esempio di giocattolo
s = "asdfasd a_b dsfd"
Voglio s = "asdfasd a'b dsfd"
Ovvero: trova due caratteri separati da un trattino basso e sostituiscilo con un apostrofo
Tentativo:
re.sub("[a-z](_)[a-z]","'",s)
# "asdfasd ' dsfd"
Pensavo che ()
dovessero risolvere questo problema?
Ancora più confuso è il fatto che sembra che abbiamo trovato con successo il personaggio che vogliamo sostituire:
re.findall("[a-z](_)[a-z]",s)
#['_']
perché questo non viene sostituito?
Grazie
Risposte
Usa modelli di sguardo in avanti e indietro:
re.sub("(?<=[a-z])_(?=[a-z])","'",s)
I motivi Guarda avanti / dietro hanno larghezza zero e quindi non sostituiscono nulla.
UPD:
- Il problema era che
re.sub
sostituirà l'intera espressione corrispondente, inclusa la lettera precedente e quella successiva. re.findall
era ancora corrispondente all'intera espressione, ma aveva anche un gruppo (la parentesi all'interno), che hai osservato. L'intera partita era fermaa_b
- Le espressioni lookahead / lookbehind verificano che la ricerca sia preceduta / seguita da un modello, ma non la includono nella corrispondenza.
- un'altra opzione era creare diversi gruppi e inserirli nella sostituzione:
re.sub("([a-z])_([a-z])", r"\1'\2", s)
Quando si utilizza re.sub
, il testo da conservare deve essere catturato, il testo da rimuovere no.
Uso
re.sub(r"([a-z])_(?=[a-z])",r"\1'",s)
Vedi la prova .
SPIEGAZIONE
NODE EXPLANATION
--------------------------------------------------------------------------------
( group and capture to \1:
--------------------------------------------------------------------------------
[a-z] any character of: 'a' to 'z'
--------------------------------------------------------------------------------
) end of \1
--------------------------------------------------------------------------------
_ '_'
--------------------------------------------------------------------------------
(?= look ahead to see if there is:
--------------------------------------------------------------------------------
[a-z] any character of: 'a' to 'z'
--------------------------------------------------------------------------------
) end of look-ahead
Codice Python :
import re
s = "asdfasd a_b dsfd"
print(re.sub(r"([a-z])_(?=[a-z])",r"\1'",s))
Produzione:
asdfasd a'b dsfd
Il re.sub
sostituirà tutto ciò che ha trovato.
C'è un modo più generale per risolvere il tuo problema e non è necessario modificare nuovamente la tua espressione regolare.
Codice di seguito:
import re
s = 'Data: year=2018, monthday=1, month=5, some other text'
reg = r"year=(\d{4}), monthday=(\d{1}), month=(\d{1})"
r = "am_replace_str"
def repl(match):
_reg = "|".join(match.groups())
return re.sub(_reg, r,match.group(0)) if _reg else r
#
re.sub(reg,repl, s)
produzione: 'Data: year=am_replace_str, monthday=am_replace_str, month=am_replace_str, some other text'
Ovviamente, se il tuo caso non contiene gruppi, il tuo codice potrebbe essere questo:
import re
s = 'Data: year=2018, monthday=1, month=5, some other text'
reg = r"year=(\d{4}), monthday=(\d{1}), month=(\d{1})"
r = "am_replace_str"
def repl(match):
_reg = "|".join(match.groups())
return re.sub(_reg, r,match.group(0))
#
re.sub(reg,repl, s)