如何使用tr替换多组?

如何使用tr替换多组?

我想用tr替换数字0-5和替换A数字。6-9B

我尝试使用sed这样做:

sed 's/[0-4]/</; s/[6-9]/>/' 

但它只能工作一次,所以例如,如果我写它,123它只会带有A23而不是AAA.

答案1

对于sed,您需要添加g,以便它将替换每行中出现的所有内容:

sed 's/[0-4]/A/g;s/[5-9]/B/g'

使用tr,您可以链接两个trs:

tr '0-4' A | tr '6-9' B

或显式提供字符转换:

tr 0123456789 AAAAABBBBB

甚至:

tr 0-45-9 AAAAABBBBB

(但我发现后者的可读性较差,因为 1-1 映射不是立即可见的)。

重复的Bs 可以缩写(tr根据需要重复最后一个字符),并且可以合并范围:

tr 0123456789 AAAAAB
tr 0-9 AAAAAB

对于更复杂的替换,拆分命令可以帮助使其目的更加明显:

tr 0123456789 \
   AAAAABBBBB

或者,利用引用范围与这种情况下的扩展长度相匹配的事实:

tr '0-4''5-9' \
   AAAAABBBBB

我假设范围分割是 0-4 和 5-9,以均匀分割,如示例的第一个命令中所示sed。可以根据需要调整范围。

答案2

/g使用末尾的量词对所有字符进行全局替换。如果没有它,替换将在第一个匹配的字符处结束,并将不是随后继续进行。

另一种用于sed音译字符的方法(类似于tr)在 GNU 和 POSIX 中均可用

sed 'y/123456789/AAAAABBBB/'

答案3

POSIXly:

tr 0123456789  AAAAAABBBB
tr 0123456789 '[A*6][B*4]'
tr 0123456789 '[A*6][B*]'
sed 's/[012345]/A/g; s/[6789]/B/g'
sed 'y/0123456789/AAAAAABBBB/'

一些注意事项:

  • tr 012345 A不是 POSIX,因为第二组的大小与第一组的大小不同。
  • tr 0-5 AAAAAA仅保证在 POSIX/C 语言环境中工作。
  • sed 's/[0-5]/A/g'对于非 POSIX 语言环境中的where[0-5]可以匹配比 012345 更多的内容也是如此。

请注意,截至 2020 年,与 的 GNU 实现tr相反, 的 GNU 实现sed不支持多字节(尽管我相信存在一些补丁来添加某种程度的支持),因此这些tr方法不能在 GNU 上使用使用 GB18030 等字符集的语言环境中的系统,其中大多数字符的编码包含十进制数字的编码。

例如:

$ printf '%s\n' "$LANG"
zh_CN.gb18030
$ locale charmap
GB18030
$ locale title
Chinese locale for Peoples Republic of China
$ tr --version
tr (GNU coreutils) 8.30
[...]
$ sed --version
sed (GNU sed) 4.7
[...]

$ echo '£12' | tr 0123456789 '[A*6][B*4]'
丄凙AA
$ echo '£12' | sed 'y/0123456789/AAAAAABBBB/'
£AA

这是因为£(英镑符号)被编码为字节 0x81 0x30 0x84 0x35,其中 0x30 也是 的编码0,0x35 也是 的编码5

$ echo '£12' | LC_ALL=C od -vtx1 -tc
0000000  81  30  84  35  31  32  0a
        201   0 204   5   1   2  \n
0000007
$ echo '£12' | tr 0123456789 '[A*6][B*5]' | LC_ALL=C od -vtx1 -tc
0000000  81  41  84  41  41  41  0a
        201   A 204   A   A   A  \n
0000007

答案4

假设范围是 0-4 和 5-9:

tr 0-9 AAAAAB

或者

sed y_0123456789_AAAAABBBBB_

相关内容