Usando Awk:
#!/usr/bin/awk -f
BEGIN {
FS = OFS = ""
table["a"] = "e"
table["x"] = "ch"
# and so on...
}
{
for (i = 1; i <= NF; ++i) {
if ($i in table) {
$i = table[$i]
}
}
}
1
Uso:
awk -f script.awk file
Prueba:
# echo "the quick brown fox jumps over the lazy dog" | awk -f script.awk
the quick brown foch jumps over the lezy dog
No es una respuesta, solo para mostrar una forma idiomática más breve de completar el table[]
matriz de la respuesta de @konsolebox como se discutió en los comentarios relacionados:
BEGIN {
split("a e b", old)
split("x ch o", new)
for (i in old)
table[old[i]] = new[i]
FS = OFS = ""
}
por lo tanto, la asignación de caracteres antiguos a nuevos se muestra claramente en que el carácter en la primera división () se asigna a los caracteres debajo de él y para cualquier otra asignación que desee, solo necesita cambiar la(s) cadena(s) en el split(), no cambie las asignaciones explícitas de 26 a table[].
Incluso puede crear una secuencia de comandos general para realizar asignaciones y simplemente pasar las cadenas antiguas y nuevas como variables:
BEGIN {
split(o, old)
split(n, new)
for (i in old)
table[old[i]] = new[i]
FS = OFS = ""
}
luego en shell algo como esto:
old="a e b"
new="x ch o"
awk -v o="$old" -v b="$new" -f script.awk file
y puede protegerse de sus propios errores que pueblan las cadenas, por ejemplo:
BEGIN {
numOld = split(o, old)
numNew = split(n, new)
if (numOld != numNew) {
printf "ERROR: #old vals (%d) != #new vals (%d)\n", numOld, numNew | "cat>&1"
exit 1
}
for (i=1; i <= numOld; i++) {
if (old[i] in table) {
printf "ERROR: \"%s\" duplicated at position %d in old string\n", old[i], i | "cat>&2"
exit 1
}
if (newvals[new[i]]++) {
printf "WARNING: \"%s\" duplicated at position %d in new string\n", new[i], i | "cat>&2"
}
table[old[i]] = new[i]
}
}
¿No sería bueno saber si escribió que b se corresponde con x y luego escribió por error que b se corresponde con y? Lo anterior realmente es la mejor manera de hacer esto, pero tu decisión, por supuesto.
Aquí hay una solución completa como se discute en los comentarios a continuación
BEGIN {
numOld = split("a e b", old)
numNew = split("x ch o", new)
if (numOld != numNew) {
printf "ERROR: #old vals (%d) != #new vals (%d)\n", numOld, numNew | "cat>&1"
exit 1
}
for (i=1; i <= numOld; i++) {
if (old[i] in table) {
printf "ERROR: \"%s\" duplicated at position %d in old string\n", old[i], i | "cat>&2"
exit 1
}
if (newvals[new[i]]++) {
printf "WARNING: \"%s\" duplicated at position %d in new string\n", new[i], i | "cat>&2"
}
map[old[i]] = new[i]
}
FS = OFS = ""
}
{
for (i = 1; i <= NF; ++i) {
if ($i in map) {
$i = map[$i]
}
}
print
}
Cambié el nombre del table
matriz como map
solo porque iMHO eso representa mejor el propósito de la matriz.
guarde lo anterior en un archivo script.awk
y ejecútelo como awk -f script.awk inputfile
Esto se puede hacer de manera bastante concisa usando una sola línea de Perl:
perl -pe '%h=(a=>"xy",c=>"z"); s/(.)/defined $h{$1} ? $h{$1} : $1/eg'
o equivalente (gracias jaypal):
perl -pe '%h=(a=>"xy",c=>"z"); s|(.)|$h{$1}//=$1|eg'
%h
es un hash que contiene los caracteres (claves) y sus sustituciones (valores). s
es el comando de sustitución (como en sed). El g
modificador significa que la sustitución es global y el e
significa que la pieza de repuesto se evalúa como una expresión. Captura cada carácter uno por uno y los sustituye con el valor en el hash si existe, de lo contrario mantiene el valor original. El -p
cambiar significa que cada línea en la entrada se imprime automáticamente.
Probarlo:
$ perl -pe '%h=(a=>"xy",c=>"z"); s|(.)|$h{$1}//=$1|eg' <<<"abc"
xybz