使用 bash 将字符串翻译成另一种语言
Translating strings to another language using bash
我创建了一个脚本,可以获取拉丁字符和希腊字符的人名和姓氏。我的挑战是将所有希腊字符翻译成拉丁字符,以便为他们的个人资料创建更多可能的 Facebook 链接,但仅使用 bash,仅此而已,例如 python、ruby 等。
我创建了一个类似于散列 table 文件的东西,它看起来像这样(看下面)并遵循一个简单的规则...每条记录都用逗号分隔,1st 字段表示字母具有的 number 其他表达方式,2nd 字段表示 greek[=我要查找的第 32=] 个字母和接下来的字母 (3rd and/or 4th) 表示希腊字母在 拉丁语方式。
0,Α,A
0,Β,B
0,Γ,G
0,Δ,D
0,Ε,E
0,Ζ,Z
0,Η,I
0,Θ,TH
0,Ι,I
0,Κ,K
0,Λ,L
0,Μ,M
0,Ν,N
1,Ξ,X,KS
0,Ο,O
0,Π,P
0,Ρ,R
0,Σ,S
0,Τ,T
1,Υ,Y,U
1,Φ,F,PH
1,Χ,CH,H
0,Ψ,PS
1,Ω,O,W
现在,经过许多小时的研究,我还没有找到完全适合我需要的东西。
我试过,但没有成功,是将一个字符串传递给函数,然后函数加载它必须从它的散列 table 翻译的每个字母,并将它输出到一个名为 [ 的文件=42=]
function greek2latin()
{
#usage: greek2latin <string>
while read hashed
do
greek=$(echo $hashed | cut -d',' -f2)
latin0=$(echo $hashed | cut -d',' -f3)
echo | tr '$greek' '$latin0' > "$PWD"/data/data.tr
#note that "1" is read as string, thus compared as one
#maybe I need to change that later on
if [ $(echo "$hashed" | cut -d',' -f1) == "1" ]
then
latin1=$(echo $hashed | cut -d',' -f4)
echo | tr '$greek' '$latin1' > "$PWD"/data/data.tr
fi
done < "$PWD"/data/hashed.synonyms/greek2latin
}
有人可以告诉我为什么它没有按预期工作吗?如果有任何帮助,我将不胜感激。
谢谢! :)
(0) 初步地,取语言 A 中的一个单词并将每个字母(或有时是字母对)更改为语言 B 中具有(大致)相同发音的字母(或对),但不更改为 word在B语言中,不是翻译,是音译。此外,您的 'table' 文件未经过哈希处理或未经过哈希处理;它只是一个包含所需翻译的文件。
(1) 你的脚本没有改变任何东西,因为 shell 变量没有在单引号内扩展;事实上 单引号 中没有任何特殊含义,如 this quite terse item in the bash manual:
所指定
Enclosing characters in single quotes (‘'’) preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.
因此您告诉 tr
将 $
替换为 $
,将 g
替换为 l
,将 r
替换为 a
,e
与 i
,以及 k
与 n
。由于您的输入可能不包含任何 $ g r e k
这什么都不做。
(2A) 如果您通过使用扩展 $var
的双引号来修复此问题(以及此处不相关的其他一些内容),在某些情况下它仍然无法正常工作,因为 tr
逐字符替换。因此,如果你 运行 tr
第一个参数 xi (一个字符,见下一个)和第二个参数 KS
(两个字符)它会将任何(和所有)xi 转换为 K
并且永远不要将 S
用于任何事情。
要将单个字符转换为可能包含多个字符的字符串,请考虑 sed
或类似 awk
或 perl
的内容。或者因为你想要 'only bash' 你可以使用 bash 自己的字符串替换像 ${1//$greek/$latin}
(2B) 另一个可能的问题是许多(但绝对不是全部)带有 GNU shell bash
的系统也有 GNU coreutils 实现tr
个 不支持多字节 字符,即 UTF-8。现在大多数 'multi-lingual'(更准确地说 non-English/non-ASCII)material 都是用 UTF-8 编码的。然而,有一个 ISO-8859 single-octet code, variant -7, for Greek,如果您的输入(脚本和数据)是 8859-7 或可以转换成它,那么 GNU tr
可以使用,除了多字符的情况。
(3) 您不需要多个 cut
进程来解析您的输入行; shell read
可以做到:
while IFS=, read flag greek latin0 latin1; do
echo "${1//$greek/$latin0}" >>output
if [ "$flag" == "1" ]; then echo "${1//$greek/$latin1}" >>output; fi
done <translationsfile
(4) echo
对于某些数据可能会出现故障,尽管该数据对于您的用例来说可能不太可能。 The safer and more portable method is printf.
(5) 您真的不需要标志列来告诉您 'latin1' 列何时存在,您可以只测试 $latin1
的(值)是否为 none空。
(6) 您的逻辑会为每个字母创建一个或两个单独的翻译。如果输入名称有例如重复 none 的 5 个字母,您将创建 5 个翻译,每个翻译只有一个字母从希腊语变为拉丁语,另外 20 个或其他任何字母(我没数过)完全没有变化。我经常看到人们使用将 所有 个字母音译成另一种语言的名字,这可能至少对某些人来说更方便,但是一个名字中的一些字母是一种语言,一个字母是另一种语言在我看来,另一种语言对 每个人 来说都不方便,因此毫无用处。我会从输入名称开始并音译 所有 字母——要么是值中的所有字母(可能有一个实际的散列 table,这可以在最近 bash 与关联数组)或所有可能的数组。我留下这个,这样你仍然可以完成你的作业。
(7) 最后也是最不重要的一点是,您永远不需要将 $PWD
指定为文件的起始路径,因为相对路径名会自动从工作目录开始;这就是 'working directory' 的意思 。如果你想强调它是相对的,一个常见的约定是从./relative/path/to/whatever
开始,这在技术上仍然是多余的但是是一个可见的提醒。
我创建了一个脚本,可以获取拉丁字符和希腊字符的人名和姓氏。我的挑战是将所有希腊字符翻译成拉丁字符,以便为他们的个人资料创建更多可能的 Facebook 链接,但仅使用 bash,仅此而已,例如 python、ruby 等。
我创建了一个类似于散列 table 文件的东西,它看起来像这样(看下面)并遵循一个简单的规则...每条记录都用逗号分隔,1st 字段表示字母具有的 number 其他表达方式,2nd 字段表示 greek[=我要查找的第 32=] 个字母和接下来的字母 (3rd and/or 4th) 表示希腊字母在 拉丁语方式。
0,Α,A
0,Β,B
0,Γ,G
0,Δ,D
0,Ε,E
0,Ζ,Z
0,Η,I
0,Θ,TH
0,Ι,I
0,Κ,K
0,Λ,L
0,Μ,M
0,Ν,N
1,Ξ,X,KS
0,Ο,O
0,Π,P
0,Ρ,R
0,Σ,S
0,Τ,T
1,Υ,Y,U
1,Φ,F,PH
1,Χ,CH,H
0,Ψ,PS
1,Ω,O,W
现在,经过许多小时的研究,我还没有找到完全适合我需要的东西。 我试过,但没有成功,是将一个字符串传递给函数,然后函数加载它必须从它的散列 table 翻译的每个字母,并将它输出到一个名为 [ 的文件=42=]
function greek2latin()
{
#usage: greek2latin <string>
while read hashed
do
greek=$(echo $hashed | cut -d',' -f2)
latin0=$(echo $hashed | cut -d',' -f3)
echo | tr '$greek' '$latin0' > "$PWD"/data/data.tr
#note that "1" is read as string, thus compared as one
#maybe I need to change that later on
if [ $(echo "$hashed" | cut -d',' -f1) == "1" ]
then
latin1=$(echo $hashed | cut -d',' -f4)
echo | tr '$greek' '$latin1' > "$PWD"/data/data.tr
fi
done < "$PWD"/data/hashed.synonyms/greek2latin
}
有人可以告诉我为什么它没有按预期工作吗?如果有任何帮助,我将不胜感激。
谢谢! :)
(0) 初步地,取语言 A 中的一个单词并将每个字母(或有时是字母对)更改为语言 B 中具有(大致)相同发音的字母(或对),但不更改为 word在B语言中,不是翻译,是音译。此外,您的 'table' 文件未经过哈希处理或未经过哈希处理;它只是一个包含所需翻译的文件。
(1) 你的脚本没有改变任何东西,因为 shell 变量没有在单引号内扩展;事实上 单引号 中没有任何特殊含义,如 this quite terse item in the bash manual:
所指定Enclosing characters in single quotes (‘'’) preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.
因此您告诉 tr
将 $
替换为 $
,将 g
替换为 l
,将 r
替换为 a
,e
与 i
,以及 k
与 n
。由于您的输入可能不包含任何 $ g r e k
这什么都不做。
(2A) 如果您通过使用扩展 $var
的双引号来修复此问题(以及此处不相关的其他一些内容),在某些情况下它仍然无法正常工作,因为 tr
逐字符替换。因此,如果你 运行 tr
第一个参数 xi (一个字符,见下一个)和第二个参数 KS
(两个字符)它会将任何(和所有)xi 转换为 K
并且永远不要将 S
用于任何事情。
要将单个字符转换为可能包含多个字符的字符串,请考虑 sed
或类似 awk
或 perl
的内容。或者因为你想要 'only bash' 你可以使用 bash 自己的字符串替换像 ${1//$greek/$latin}
(2B) 另一个可能的问题是许多(但绝对不是全部)带有 GNU shell bash
的系统也有 GNU coreutils 实现tr
个 不支持多字节 字符,即 UTF-8。现在大多数 'multi-lingual'(更准确地说 non-English/non-ASCII)material 都是用 UTF-8 编码的。然而,有一个 ISO-8859 single-octet code, variant -7, for Greek,如果您的输入(脚本和数据)是 8859-7 或可以转换成它,那么 GNU tr
可以使用,除了多字符的情况。
(3) 您不需要多个 cut
进程来解析您的输入行; shell read
可以做到:
while IFS=, read flag greek latin0 latin1; do
echo "${1//$greek/$latin0}" >>output
if [ "$flag" == "1" ]; then echo "${1//$greek/$latin1}" >>output; fi
done <translationsfile
(4) echo
对于某些数据可能会出现故障,尽管该数据对于您的用例来说可能不太可能。 The safer and more portable method is printf.
(5) 您真的不需要标志列来告诉您 'latin1' 列何时存在,您可以只测试 $latin1
的(值)是否为 none空。
(6) 您的逻辑会为每个字母创建一个或两个单独的翻译。如果输入名称有例如重复 none 的 5 个字母,您将创建 5 个翻译,每个翻译只有一个字母从希腊语变为拉丁语,另外 20 个或其他任何字母(我没数过)完全没有变化。我经常看到人们使用将 所有 个字母音译成另一种语言的名字,这可能至少对某些人来说更方便,但是一个名字中的一些字母是一种语言,一个字母是另一种语言在我看来,另一种语言对 每个人 来说都不方便,因此毫无用处。我会从输入名称开始并音译 所有 字母——要么是值中的所有字母(可能有一个实际的散列 table,这可以在最近 bash 与关联数组)或所有可能的数组。我留下这个,这样你仍然可以完成你的作业。
(7) 最后也是最不重要的一点是,您永远不需要将 $PWD
指定为文件的起始路径,因为相对路径名会自动从工作目录开始;这就是 'working directory' 的意思 。如果你想强调它是相对的,一个常见的约定是从./relative/path/to/whatever
开始,这在技术上仍然是多余的但是是一个可见的提醒。