¿Cuál es una buena manera de hacer reemplazos de cadenas en un archivo usando un diccionario con mucho de pares sustituyente-sustituyente? Y por mucho , en realidad me refiero a unos 20, no mucho, pero lo suficiente como para querer organizarlos ordenadamente.
Quiero recopilar todos los pares de sustituyentes y sustituyentes en un archivo dictionary.txt
de una manera fácil de administrar, ya que necesito reemplazar muchas cosas, diga algo así:
"yes" : "no"
"stop" : "go, go, go!"
"wee-ooo" : "ooooh nooo!"
"gooodbye" : "hello"
"high" : "low"
"why?" : "i don't know"
Ahora quiero aplicar estas sustituciones en algún archivo novel.txt
.
Entonces quiero ejecutar magiccommand --magicflags dictionary.txt novel.txt
para que todas las instancias de yes
en novel.txt
se reemplazan por no
(así que incluso Bayesian
sería reemplazado por Banoian
) y todas las instancias de goodbye
en novel.txt
sería reemplazado por hello
y así sucesivamente.
Hasta ahora, las cadenas que necesito reemplazar (y reemplazar con) no tienen comillas (ni simples ni dobles) en ellas. (Sin embargo, sería bueno ver una solución que funcione bien con cadenas que contengan comillas, por supuesto).
Sé sed
y awk
/ gawk
pueden hacer ese tipo de cosas principalmente, pero ¿pueden también trabajar con tales archivos de diccionario? Parece como gawk
sería el candidato adecuado para magiccommand
, ¿cuáles son las magicflags
correctas? ? ¿Cómo necesito formatear mi dictionary.txt
? ?
Respuesta aceptada:
Aquí hay una forma 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
Cómo funciona:
El primer sed
convierte dictionary.txt
en un archivo de script (comandos de edición, uno por línea). Esto se canaliza al segundo sed
(tenga en cuenta el -f -
lo que significa leer comandos de stdin
) que ejecuta esos comandos, editando novel.txt
.
Esto requiere traducir su formato
"STRING" : "REPLACEMENT"
en un sed
comando y escapando cualquier carácter especial en el proceso para ambos LHS
y RHS
:
s/ESCAPED_STRING/ESCAPED_REPLACEMENT/g
Así que la primera sustitución
s|"(.*)"[[:blank:]]*:[[:blank:]]*"(.*)"|1
2|
convierte "STRING" : "REPLACEMENT"
en STRINGnREPLACEMENT
(n
es un carácter de nueva línea). El resultado luego se copia sobre el h
antiguo espacio.s|.*n||
elimina la primera parte manteniendo solo REPLACEMENT
entonces s|[&/]|\&|g
escapa los caracteres reservados (este es el RHS
).
Entonces ex
cambia el búfer de espera con el patrón de espacio y s|n.*||
elimina la segunda parte manteniendo solo STRING
y s|[[.*^$/]|\&|g
hace el escape (este es el LHS
).
El contenido del búfer de retención se agrega al espacio de patrón a través de G
así que ahora el contenido del espacio patrón es ESCAPED_STRINGnESCAPED_REPLACEMENT
.
La sustitución final
s|(.*)n(.*)|s/1/2/g|
lo transforma en s/ESCAPED_STRING/ESCAPED_REPLACEMENT/g