linux shell的音译脚本

问题描述 投票:5回答:4

我有多个包含字母表文本的.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字符?

linux shell sed tr
4个回答
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运行


4
投票

使用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

2
投票

这可以使用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

0
投票

使用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使你的文件可执行。

© www.soinside.com 2019 - 2024. All rights reserved.