Utilizzo di 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
Utilizzo:
awk -f script.awk file
Prova:
# echo "the quick brown fox jumps over the lazy dog" | awk -f script.awk
the quick brown foch jumps over the lezy dog
Non una risposta, solo per mostrare un modo più breve e idiomatico per popolare table[]
array dalla risposta di @konsolebox come discusso nei commenti correlati:
BEGIN {
split("a e b", old)
split("x ch o", new)
for (i in old)
table[old[i]] = new[i]
FS = OFS = ""
}
quindi la mappatura dei caratteri vecchi con quelli nuovi è chiaramente mostrata in quanto il carattere nel primo split() è mappato sui caratteri sotto di esso e per qualsiasi altra mappatura che desideri devi solo cambiare la stringa o le stringhe nel split(), non modificare le assegnazioni esplicite di 26-ish in table[].
Puoi persino creare uno script generale per eseguire le mappature e semplicemente passare le stringhe vecchie e nuove come variabili:
BEGIN {
split(o, old)
split(n, new)
for (i in old)
table[old[i]] = new[i]
FS = OFS = ""
}
quindi nella shell qualcosa di simile a questo:
old="a e b"
new="x ch o"
awk -v o="$old" -v b="$new" -f script.awk file
e puoi proteggerti dai tuoi errori nel popolare le stringhe, ad esempio:
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]
}
}
Non sarebbe utile sapere se hai scritto che b è mappato su x e poi in seguito hai scritto erroneamente che b è mappato su y? Quanto sopra è davvero il modo migliore per farlo, ma la tua chiamata ovviamente.
Ecco una soluzione completa come discusso nei commenti qui sotto
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
}
Ho rinominato il table
matrice come map
solo perché iMHO rappresenta meglio lo scopo dell'array.
salva quanto sopra in un file script.awk
ed eseguilo come awk -f script.awk inputfile
Questo può essere fatto abbastanza concisamente usando un one-liner Perl:
perl -pe '%h=(a=>"xy",c=>"z"); s/(.)/defined $h{$1} ? $h{$1} : $1/eg'
o equivalentemente (grazie jaypal):
perl -pe '%h=(a=>"xy",c=>"z"); s|(.)|$h{$1}//=$1|eg'
%h
è un hash contenente i caratteri (chiavi) e le loro sostituzioni (valori). s
è il comando di sostituzione (come in sed). Il g
modificatore significa che la sostituzione è globale e e
significa che la parte di ricambio viene valutata come un'espressione. Cattura ogni carattere uno per uno e li sostituisce con il valore nell'hash se esiste, altrimenti mantiene il valore originale. Il -p
switch significa che ogni riga nell'input viene stampata automaticamente.
Provalo:
$ perl -pe '%h=(a=>"xy",c=>"z"); s|(.)|$h{$1}//=$1|eg' <<<"abc"
xybz