在流中用 1 替换 0 或反之亦然的最快方法是什么?

在流中用 1 替换 0 或反之亦然的最快方法是什么?

0给定一个由s 和s组成的字符串1,我的目标是用 1 替换 0,反之亦然。例子:

输入

111111100000000000000

预期输出

000000011111111111111

我尝试了以下sed命令,但没有成功

echo '111111100000000000000' | sed -e 's/0/1/g ; s/1/0/g'
000000000000000000000

我缺少什么?

答案1

您可以使用tr为此,其主要目的是字符翻译:

echo 111111100000000000000 | tr 01 10

您的sed命令将所有 0 替换为 1,从而生成一个仅包含 1 的字符串(原始 1 和所有替换的 0),然后将所有 1 替换为 0,从而生成一个仅包含 0 的字符串。

在长流上,tr比 更快sed;对于 100MiB 文件:

$ time tr 10 01 < bigfileof01s > /dev/null
tr 10 01 < bigfileof01s > /dev/null  0.07s user 0.03s system 98% cpu 0.100 total

$ time sed y/10/01/ < bigfileof01s > /dev/null
sed y/10/01/ < bigfileof01s > /dev/null  3.91s user 0.11s system 99% cpu 4.036 total

答案2

虽然tr是适合这项工作的工具sed您可以使用y(音译)命令而不是(替换)命令来完成此s操作:

$ echo '111111100000000000000' | sed 'y/01/10/'
000000011111111111111

y基本上是sed- 的内部实现tr- 以及暗示的所有开销。

答案3

一个办法是echo "111111100000000000000" | sed 's/1/2/g;s/0/1/g;s/2/0/g'

答案4

如果您的字符串仅包含一行并且仅由 0 和 1 组成,那么您可以使用此

echo "111111100000000000000" |
    perl -e 'while (read(STDIN, $b, 1)) { print chr(ord($b) ^ 1); } print "\n";'

如果字符串可以包含多行,则只需更改perl -eperl -ne并更改读取字节的方式(因为read需要文件句柄)

echo -e "111111100000000000000\n0001111010101" |
    perl -ne 'while (/(.)/g) { print chr(ord($1)^1) } print "\n"'

然而,这样每一行都被分成一个字符串,因此对于大文件来说可能不是很有效。在这种情况下,需要进行一些检查

echo "122111111034000000000abc0000" | perl -e 'while (read(STDIN, $b, 1)) {
    print ($b eq '0' or $b eq '1' ? chr(ord($b) ^ 1) : $b) } print "\n";'

正如您所看到的,这种方式也适用于包含'0'和以外的字符的字符串'1'

相关内容