Qual è un buon modo per sostituire le stringhe in un file usando un dizionario con molto di coppie sostituente-sostituente? E di molto , in realtà intendo circa 20, non molti, ma abbastanza da poterli organizzare ordinatamente.
Vorrei raccogliere tutte le coppie sostituente-sostituente in un file dictionary.txt
in un modo facile da gestire, dal momento che ho bisogno di sostituire molte cose, dì come:
"yes" : "no"
"stop" : "go, go, go!"
"wee-ooo" : "ooooh nooo!"
"gooodbye" : "hello"
"high" : "low"
"why?" : "i don't know"
Ora voglio applicare queste sostituzioni in alcuni file novel.txt
.
Quindi voglio eseguire magiccommand --magicflags dictionary.txt novel.txt
in modo che tutte le istanze di yes
in novel.txt
sono sostituiti da no
(quindi anche Bayesian
verrebbe sostituito da Banoian
) e tutte le istanze di goodbye
in novel.txt
verrebbe sostituito da hello
e così via.
Finora, le stringhe che devo sostituire (e sostituire con) non contengono virgolette (né singole né doppie). (Sarebbe bello, tuttavia, vedere una soluzione che funziona bene con stringhe contenenti virgolette, ovviamente.)
Conosco sed
e awk
/ gawk
possono fare queste cose principalmente, ma possono anche funzionare con tali file di dizionario? Sembra gawk
sarebbe il candidato giusto per magiccommand
, quali sono i magicflags
corretti ? Come devo formattare il mio dictionary.txt
?
Risposta accettata:
Ecco un modo con sed
:
sed '
s|"(.*)"[[:blank:]]*:[[:blank:]]*"(.*)"|1
2|
h
s|.*n||
s|[&/]|\&|g
x
s|n.*||
s|[[.*^$/]|\&|g
G
s|(.*)n(.*)|s/1/2/g|
' dictionary.txt | sed -f - novel.txt
Come funziona:
Il primo sed
trasforma dictionary.txt
in un file di script (comandi di modifica, uno per riga). Questo viene inviato al 2° sed
(notare il -f -
il che significa leggere i comandi da stdin
) che esegue quei comandi, modificando novel.txt
.
Ciò richiede la traduzione del formato
"STRING" : "REPLACEMENT"
in un sed
comando e l'escape di qualsiasi carattere speciale nel processo sia per LHS
e RHS
:
s/ESCAPED_STRING/ESCAPED_REPLACEMENT/g
Quindi la prima sostituzione
s|"(.*)"[[:blank:]]*:[[:blank:]]*"(.*)"|1
2|
trasforma "STRING" : "REPLACEMENT"
in STRINGnREPLACEMENT
(n
è un carattere di nuova riga). Il risultato viene quindi copiato su h
vecchio spazio.s|.*n||
cancella la prima parte mantenendo solo REPLACEMENT
quindi s|[&/]|\&|g
esce dai caratteri riservati (questo è il RHS
).
Quindi ex
cambia il buffer di attesa con lo spazio del pattern e s|n.*||
cancella la seconda parte mantenendo solo STRING
e s|[[.*^$/]|\&|g
fa l'escape (questo è il LHS
).
Il contenuto del buffer di attesa viene quindi aggiunto allo spazio del pattern tramite G
quindi ora il contenuto dello spazio del modello è ESCAPED_STRINGnESCAPED_REPLACEMENT
.
La sostituzione finale
s|(.*)n(.*)|s/1/2/g|
lo trasforma in s/ESCAPED_STRING/ESCAPED_REPLACEMENT/g