Použití 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
Použití:
awk -f script.awk file
Test:
# echo "the quick brown fox jumps over the lazy dog" | awk -f script.awk
the quick brown foch jumps over the lezy dog
Není to odpověď, jen ukazuje stručnější, idiomatický způsob, jak vyplnit table[]
pole z odpovědi @konsolebox, jak je popsáno v souvisejících komentářích:
BEGIN {
split("a e b", old)
split("x ch o", new)
for (i in old)
table[old[i]] = new[i]
FS = OFS = ""
}
takže mapování starých na nové znaky je jasně ukázáno v tom, že znak v prvním split() je mapován na znak(y) pod ním a pro jakékoli další mapování, které chcete, stačí změnit řetězec(y) v split(), nemění 26-ti explicitní přiřazení k tabulce[].
Můžete dokonce vytvořit obecný skript pro mapování a pouze předat staré a nové řetězce jako proměnné:
BEGIN {
split(o, old)
split(n, new)
for (i in old)
table[old[i]] = new[i]
FS = OFS = ""
}
pak v shellu něco takového:
old="a e b"
new="x ch o"
awk -v o="$old" -v b="$new" -f script.awk file
a můžete se chránit před vlastními chybami při vyplňování řetězců, např.:
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]
}
}
Nebylo by dobré vědět, kdybyste napsal, že b mapuje x a později omylem napsal, že b mapuje y? Výše uvedené je opravdu nejlepší způsob, jak toho dosáhnout, ale samozřejmě vaše volání.
Zde je jedno kompletní řešení, jak je diskutováno v komentářích níže
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
}
Přejmenoval jsem table
pole jako map
jen proto, že iMHO lépe reprezentuje účel pole.
výše uložte do souboru script.awk
a spusťte jej jako awk -f script.awk inputfile
To lze provést poměrně stručně pomocí jednořádkového perlu:
perl -pe '%h=(a=>"xy",c=>"z"); s/(.)/defined $h{$1} ? $h{$1} : $1/eg'
nebo ekvivalentně (díky jaypal):
perl -pe '%h=(a=>"xy",c=>"z"); s|(.)|$h{$1}//=$1|eg'
%h
je hash obsahující znaky (klíče) a jejich substituce (hodnoty). s
je substituční příkaz (jako v sed). g
modifikátor znamená, že substituce je globální a e
znamená, že náhradní díl je vyhodnocen jako výraz. Zachytí každý znak jeden po druhém a nahradí je hodnotou v hash, pokud existuje, jinak zachová původní hodnotu. -p
přepínač znamená, že každý řádek na vstupu se automaticky vytiskne.
Testování:
$ perl -pe '%h=(a=>"xy",c=>"z"); s|(.)|$h{$1}//=$1|eg' <<<"abc"
xybz