如何将某些字符一对一音译,保留某些字符不变,并将其他字符替换为相同的目标字符?

5 sed text-processing tr

我有一个名为file.txt包含:

MAL TIRRUEZF CR MAL RKZYIOL EX MAL OIY UAE RICF "MAL ACWALRM DYEUPLFWL CR ME DYEU MAIM UL IZL RKZZEKYFLF GH OHRMLZH"
Run Code Online (Sandbox Code Playgroud)

我希望将字符替换如下:

M = T
A = H
L = E
C = O
R = F
E = I
X = S
(Any other letter) = _
(Anything else) = (itself)
Run Code Online (Sandbox Code Playgroud)

我有固定字符覆盖:

tr MALCREX THEOFIS < file.txt
Run Code Online (Sandbox Code Playgroud)

或者:

sed 'y/MALCREX/THEOFIS/' < file.txt
Run Code Online (Sandbox Code Playgroud)

但我怎样才能执行我提到的最后两条规则呢?

ilk*_*chu 12

我认为您可以利用这样一个事实:对于许多实际实现,如果字符在第一个集合中重复tr,则最后一个实例生效。与重复语法相结合,您无需显式列出转换表中未出现的字母即可完成此操作。

对于 GNU 版本的 tr,以及我 Mac 上任何基于 FreeBSD 的版本,如下:

tr 'A-ZMALCREX' '[_*26]THEOFIS'
Run Code Online (Sandbox Code Playgroud)

轮流

MAL TIRRUEZF CR MAL RKZYIOL EX MAL OIY UAE RICF "MAL ACWALRM DYEUPLFWL CR ME DYEU MAIM UL IZL RKZZEKYFLF GH OHRMLZH"
Run Code Online (Sandbox Code Playgroud)

进入

THE __FF_I__ OF THE F_____E IS THE ___ _HI F_O_ "THE HO_HEFT __I__E__E OF TI __I_ TH_T _E __E F___I___E_ __ __FTE__"
Run Code Online (Sandbox Code Playgroud)

当然,假设A-Z生成恰好 26 个字符,并且我不确定这是否适用于每个 tr 实现的每个语言环境。它应该在 C 语言环境中工作,例如 GNU 版本的 tr 无论如何除了原始 8 位字符之外不支持任何内容。

上面的代码在 Busybox 中不起作用,但这似乎是因为它不支持重复语法。在那里,您必须手动执行此操作:

busybox tr 'A-ZMALCREX' '__________________________THEOFIS'
Run Code Online (Sandbox Code Playgroud)

(即 26 个下划线)

对于简单的基于表的实现来说,使用重复字符覆盖相同字符的早期实例是很自然的。如果您的tr实施方式不同,您将需要使用其他答案中的解决方案。


roa*_*ima 6

比其他几个建议稍长,但可能更容易理解。

第一个建议:将不需要的字母映射到_然后转置剩余的集合。

tr BDFGHIJKNOPQSTUVWYZ _ <file | tr MALCREX THEOFIS
THE __FF_I__ OF THE F_____E IS THE ___ _HI F_O_
Run Code Online (Sandbox Code Playgroud)

第二个建议:在一个命令中完成所有操作。(GNU 和 BSD根据需要对替换源映射中的所有未映射字符隐tr式重复替换目标的最后一个字符 ( ),但POSIX将这种行为简单地标记为unspecified。)_

tr MALCREXBDFGHIJKNOPQSTUVWYZ THEOFIS_ <file
THE __FF_I__ OF THE F_____E IS THE ___ _HI F_O_
Run Code Online (Sandbox Code Playgroud)


sch*_*ity 5

我建议这个perl替代方案:

\n
$ perl -pe \'s/(?![MALCREX])[A-Z]/_/g;y/MALCREX/THEOFIS/\' file \nTHE __FF_I__ OF THE F_____E IS THE ___ _HI F_O_ "THE HO_HEFT __I__E__E OF TI __I_ TH_T _E __E F___I___E_ __ __FTE__"\n
Run Code Online (Sandbox Code Playgroud)\n

它执行先行断言,查找范围内的所有字符A-Z(除了 )MALCREX,然后按照您的sed命令执行替换。

\n

正如St\xc3\xa9phane Chazelas 所评论的,该解决方案的优点是[A-Z]可以用\\wor替换\\pL(并且可能添加-Mopen=locale以处理语言环境中的所有字符),因此它可以处理所有类型的字母。

\n
\n

另一种方法是比利叔叔的评论所建议的:

\n
perl -pe y/MALCREXA-Z/THEOFIS_/\n
Run Code Online (Sandbox Code Playgroud)\n