bash-当字符串由未知长度组成但同一字符时,多字符串更换

发布于 2025-01-18 10:50:59 字数 506 浏览 2 评论 0原文

假设一个多行文本字符串,其中某些行以键字符开始(在我们的情况下为“#”)。进一步假设您希望用不同的字符替换目标字符的所有实例(在我们的情况下)更多相邻的副本(例如“ 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或其他)可以正确进行所需的替换?

Assume a multi-line text string in which some lines start with a key-character ("#" in our case). Further assume that you wish to replace all instances of a target character ("o" in our case) with a different character ("O" in our case), if - and only if - that target character occurs as a string of two or more adjacent copies (e.g., "ooo"). This replacement is to be done in all lines that do not start with the key-character and must be case-sensitive.

For example, the following lines ...

#Foo bar
Foo bar
#Baz foo
Baz foo

are supposed to be converted into:

#Foo bar
FOO bar
#Baz foo
Baz fOO

The following attempt using sed does not retain the correct number of target characters:

$ 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

What code (with sed or otherwise) would conduct the desired replacement correctly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一枫情书 2025-01-25 10:51:00

使用 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

Using 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
沒落の蓅哖 2025-01-25 10:51:00

这可能对您有用 (GNU sed):

sed -E '1{x;s/^/O/;x}
        /^#/b
       :a;/oo+/!b;s/oo+/\n&\n/;tb
       :b;G;s/\n\n(.*)\n.$/\1/;ta;s/\n[^\n](.*\n.*)\n(.)$/\2\n\1/;tb' file

总而言之,使用指定的一个或多个字符(在本例中为 O)来替换起始位置的两个或多个 o一行不是#

用指定的字符填充保留空间。

如果该行以 # 开头,则换行。

如果该行不包含两个或o,则换行。

否则,用换行符将两个或多个 o 括起来。

附加替换字符,然后用指定字符替换两个换行符之间的非换行符。

当当前 o 组的所有替换项均已替换后,请按上述方式继续检查更多内容。

找到所有替换后,打印修改后的行。


允许多次替换的解决方案:

sed -E '1{x;s/^/oOxX/;x}
        /^#/b;
        :a;G;/((.)\2+)(.*\n(..)*\2)/!s/\n.*//;t;s//\n\1\n\3/;tb
        :b;s/\n\n(.*)\n.*$/\1/;ta;s/\n(.)(.*\n.*\n(..)*\1(.))/\4\n\2/;tb' file

This might work for you (GNU sed):

sed -E '1{x;s/^/O/;x}
        /^#/b
       :a;/oo+/!b;s/oo+/\n&\n/;tb
       :b;G;s/\n\n(.*)\n.$/\1/;ta;s/\n[^\n](.*\n.*)\n(.)$/\2\n\1/;tb' file

In overview, use a designated character or characters (in this case O) to replace two or more o's where the start of a line is not #.

Prime the hold space with the designated character.

If the line starts with #, break out.

If the line does not contain two or o's, break out.

Otherwise, surround the two or more o's by newlines.

Append the replacement character and then replace non-newline characters between two newlines with the designated character.

When all replacements for the current set of o's have been replaced, check for more by continuing as above.

Once all replacements have been found, print the amended line.


A solution allowing for multiple replacements:

sed -E '1{x;s/^/oOxX/;x}
        /^#/b;
        :a;G;/((.)\2+)(.*\n(..)*\2)/!s/\n.*//;t;s//\n\1\n\3/;tb
        :b;s/\n\n(.*)\n.*$/\1/;ta;s/\n(.)(.*\n.*\n(..)*\1(.))/\4\n\2/;tb' file
病女 2025-01-25 10:50:59

您可以使用 Perl:

echo -e "#Foo bar\nFoo bar\n#Baz foo\nBaz foo" | perl -pe 's/^#.*(*SKIP)(*F)|o{2,}/"O" x length(
amp;)/ge'

这里,^#.*(*SKIP)(*F) 匹配并跳过以 # 开头的所有行,然后是 o{2, } 匹配两个或多个 o 字符,"O" x length($&) 将这些匹配替换为 O重复匹配大小的次数($& 是匹配值)。请注意 g 后面的 e 标志,用于计算右侧的字符串。

请参阅在线演示

#!/bin/bash
s="#Foo bar
Foo bar
#Baz foo
Baz foo"
perl -pe 's/^#.*(*SKIP)(*F)|o{2,}/"O" x length(
amp;)/ge' <<< "$s"

输出:

#Foo bar
FOO bar
#Baz foo
Baz fOO

You can use Perl:

echo -e "#Foo bar\nFoo bar\n#Baz foo\nBaz foo" | perl -pe 's/^#.*(*SKIP)(*F)|o{2,}/"O" x length(
amp;)/ge'

Here, ^#.*(*SKIP)(*F) matches and skips all lines starting with #, then o{2,} matches two or more o chars, and "O" x length($&) replaces these matches with O that is repeated the match size times ($& is the match value). Note the e flag after g that is used to evaluate the string on the right-hand side.

See the online demo:

#!/bin/bash
s="#Foo bar
Foo bar
#Baz foo
Baz foo"
perl -pe 's/^#.*(*SKIP)(*F)|o{2,}/"O" x length(
amp;)/ge' <<< "$s"

Output:

#Foo bar
FOO bar
#Baz foo
Baz fOO
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文