我有多个包含字母表文本的.txt文件;我想将文本音译成另一个字母; alphabet1的一些字符与alphabet2的字符1(即a变为e)是1:1,而其他字符是1:2(即x变为ch)。
我想使用Linux shell的简单脚本来完成此操作。
使用tr或sed我可以转换1:1字符:
sed -f y/abcdefghijklmnopqrstuvwxyz/nopqrstuvwxyzabcdefghijklm/
a将成为n,b将成为等等(我认为是凯撒的密码)
但是我如何处理1:2字符?
不是答案,只是为了显示一个更简洁,惯用的方式来填充@ konsolebox的答案中的table[]
数组,如相关评论中所述:
BEGIN {
split("a e b", old)
split("x ch o", new)
for (i in old)
table[old[i]] = new[i]
FS = OFS = ""
}
所以旧的字符到新字符的映射清楚地表明,第一个split()中的char被映射到它下面的char,并且对于你想要的任何其他映射,你只需要更改字符串中的字符串。 split(),不改变对表[]的26-ish显式赋值。
您甚至可以创建一个通用脚本来进行映射,只需将旧字符串和新字符串作为变量传递:
BEGIN {
split(o, old)
split(n, new)
for (i in old)
table[old[i]] = new[i]
FS = OFS = ""
}
然后在shell中这样的事情:
old="a e b"
new="x ch o"
awk -v o="$old" -v b="$new" -f script.awk file
你可以保护自己免受你自己的错误填补,例如:
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]
}
}
知道你是否写了b映射到x然后错误写了b映射到y不是很好吗?上面真的是最好的方法,但你的呼叫当然。
这是下面评论中讨论的一个完整解决方案
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
}
我将table
数组重命名为map
,因为iMHO更能代表数组的目的。
将上述内容保存在文件script.awk
中并将其作为awk -f script.awk inputfile
运行
使用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
用法:
awk -f script.awk file
测试:
# echo "the quick brown fox jumps over the lazy dog" | awk -f script.awk
the quick brown foch jumps over the lezy dog
这可以使用Perl one-liner非常简洁地完成:
perl -pe '%h=(a=>"xy",c=>"z"); s/(.)/defined $h{$1} ? $h{$1} : $1/eg'
或等效(thanks jaypal):
perl -pe '%h=(a=>"xy",c=>"z"); s|(.)|$h{$1}//=$1|eg'
%h
是包含字符(键)及其替换(值)的哈希。 s
是替换命令(如sed中所示)。 g
修饰符意味着替换是全局的,而e
意味着替换部分被评估为表达式。它逐个捕获每个字符,并用散列中的值替换它们(如果存在),否则保留原始值。 -p
开关意味着输入中的每一行都会自动打印。
测试出来:
$ perl -pe '%h=(a=>"xy",c=>"z"); s|(.)|$h{$1}//=$1|eg' <<<"abc"
xybz
使用sed。
写一个文件transliterate.sed包含:
s/a/e/g
s/x/ch/g
然后从命令行运行以从input.txt获取音译的output.txt:
sed -f transliterate.sed input.txt > output.txt
如果你需要这个更经常考虑添加#!/bin/sed -f
作为第一行,并使用chmod 744 transliterate.sed
描述at the Wikipedia page for sed使你的文件可执行。