Bash - 当字符串包含未知长度但相同字符时的多字符字符串替换
Bash - Multi-character string replacement when strings consist of unknown length but same character
假设一个多行文本字符串,其中一些行以关键字符(在我们的示例中为“#”)开头。进一步假设您希望用不同的字符(在我们的例子中为“O”)替换目标字符(在我们的例子中为“o”)的所有实例,如果 - 并且仅当 - 该目标字符出现为两个或更多相邻副本(例如,“ooo”)。此替换将在所有不以键字符开头且必须区分大小写的行中完成。
例如,下面几行...
#Foo bar
Foo bar
#Baz foo
Baz foo
应该转换成:
#Foo bar
FOO bar
#Baz foo
Baz fOO
以下使用 sed
的尝试未保留正确数量的目标字符:
$ echo -e "#Foo bar\nFoo bar\n#Baz foo\nBaz foo" | sed '/^#/!s/o\{2,\}/O/g'
#Foo bar
FO bar
#Baz foo
Baz fO
什么代码(使用 sed
或其他)可以正确执行所需的替换?
使用sed
$ echo -e "#Foo bar\nFoo bar\n#Baz foo\nBaz foo" | sed '/#/!s/o\{2\}/\U&/'
#Foo bar
FOO bar
#Baz foo
Baz fOO
您可以使用 Perl:
echo -e "#Foo bar\nFoo bar\n#Baz foo\nBaz foo" | perl -pe 's/^#.*(*SKIP)(*F)|o{2,}/"O" x length($&)/ge'
这里,^#.*(*SKIP)(*F)
匹配并跳过所有以#
开头的行,然后o{2,}
匹配两个或多个o
字符,"O" x length($&)
替换这些与 O
匹配,重复匹配大小次数($&
是匹配值)。请注意 g
之后的 e
标志,用于评估 right-hand 侧的字符串。
参见online demo:
#!/bin/bash
s="#Foo bar
Foo bar
#Baz foo
Baz foo"
perl -pe 's/^#.*(*SKIP)(*F)|o{2,}/"O" x length($&)/ge' <<< "$s"
输出:
#Foo bar
FOO bar
#Baz foo
Baz fOO
这可能对你有用 (GNU sed):
sed -E '1{x;s/^/O/;x}
/^#/b
:a;/oo+/!b;s/oo+/\n&\n/;tb
:b;G;s/\n\n(.*)\n.$//;ta;s/\n[^\n](.*\n.*)\n(.)$/\n/;tb' file
在概述中,使用一个或多个指定字符(在本例中为 O
)替换两个或多个 o
,其中一行的开头不是 #
。
用指定的字符填充space。
如果该行以 #
开头,则打断。
如果该行不包含两个或o
,则打断。
否则,用换行符将两个或更多 o
括起来。
追加替换字符,然后用指定字符替换两个换行符之间的 non-newline 个字符。
当前 o
组的所有替换项都已替换后,继续按上述步骤检查更多项。
找到所有替换后,打印修改后的行。
允许多次替换的解决方案:
sed -E '1{x;s/^/oOxX/;x}
/^#/b;
:a;G;/((.)+)(.*\n(..)*)/!s/\n.*//;t;s//\n\n/;tb
:b;s/\n\n(.*)\n.*$//;ta;s/\n(.)(.*\n.*\n(..)*(.))/\n/;tb' file
假设一个多行文本字符串,其中一些行以关键字符(在我们的示例中为“#”)开头。进一步假设您希望用不同的字符(在我们的例子中为“O”)替换目标字符(在我们的例子中为“o”)的所有实例,如果 - 并且仅当 - 该目标字符出现为两个或更多相邻副本(例如,“ooo”)。此替换将在所有不以键字符开头且必须区分大小写的行中完成。
例如,下面几行...
#Foo bar
Foo bar
#Baz foo
Baz foo
应该转换成:
#Foo bar
FOO bar
#Baz foo
Baz fOO
以下使用 sed
的尝试未保留正确数量的目标字符:
$ echo -e "#Foo bar\nFoo bar\n#Baz foo\nBaz foo" | sed '/^#/!s/o\{2,\}/O/g'
#Foo bar
FO bar
#Baz foo
Baz fO
什么代码(使用 sed
或其他)可以正确执行所需的替换?
使用sed
$ echo -e "#Foo bar\nFoo bar\n#Baz foo\nBaz foo" | sed '/#/!s/o\{2\}/\U&/'
#Foo bar
FOO bar
#Baz foo
Baz fOO
您可以使用 Perl:
echo -e "#Foo bar\nFoo bar\n#Baz foo\nBaz foo" | perl -pe 's/^#.*(*SKIP)(*F)|o{2,}/"O" x length($&)/ge'
这里,^#.*(*SKIP)(*F)
匹配并跳过所有以#
开头的行,然后o{2,}
匹配两个或多个o
字符,"O" x length($&)
替换这些与 O
匹配,重复匹配大小次数($&
是匹配值)。请注意 g
之后的 e
标志,用于评估 right-hand 侧的字符串。
参见online demo:
#!/bin/bash
s="#Foo bar
Foo bar
#Baz foo
Baz foo"
perl -pe 's/^#.*(*SKIP)(*F)|o{2,}/"O" x length($&)/ge' <<< "$s"
输出:
#Foo bar
FOO bar
#Baz foo
Baz fOO
这可能对你有用 (GNU sed):
sed -E '1{x;s/^/O/;x}
/^#/b
:a;/oo+/!b;s/oo+/\n&\n/;tb
:b;G;s/\n\n(.*)\n.$//;ta;s/\n[^\n](.*\n.*)\n(.)$/\n/;tb' file
在概述中,使用一个或多个指定字符(在本例中为 O
)替换两个或多个 o
,其中一行的开头不是 #
。
用指定的字符填充space。
如果该行以 #
开头,则打断。
如果该行不包含两个或o
,则打断。
否则,用换行符将两个或更多 o
括起来。
追加替换字符,然后用指定字符替换两个换行符之间的 non-newline 个字符。
当前 o
组的所有替换项都已替换后,继续按上述步骤检查更多项。
找到所有替换后,打印修改后的行。
允许多次替换的解决方案:
sed -E '1{x;s/^/oOxX/;x}
/^#/b;
:a;G;/((.)+)(.*\n(..)*)/!s/\n.*//;t;s//\n\n/;tb
:b;s/\n\n(.*)\n.*$//;ta;s/\n(.)(.*\n.*\n(..)*(.))/\n/;tb' file