irishwristwatch Asked: 2022-06-10 23:23:17 +0800 CST2022-06-10 23:23:17 +0800 CST 2022-06-10 23:23:17 +0800 CST sed 将匹配中的每个字符替换为单个字符,例如 █████ 编辑 772 是否有 sed 替换函数(或其他正则表达式)将匹配模式捕获的每个字符替换为单个字符,该字符旨在覆盖或编辑匹配项?例如 Full Block █ Unicode: U+2588, UTF-8: E2 96 88 将是一个不错的选择。是否有捷径可寻? regex sed 2 个回答 Voted tripleee 2022-06-11T00:40:47+08:002022-06-11T00:40:47+08:00 替换每个字符很容易: sed 's/./█/g' file 如果您的模式更复杂,您可能必须将其拆分。例如,如果您想用三个 █:s 替换三个长度为 3 的单词,以及两个长度为 4 的单词,我将编写两个单独的规则: sed -e 's/\(one\|two\|six\)/███/g' -e 's/\(four\|five\)/████/g' file 如果你有大量不同长度的模式,也许切换到更强大的语言,比如 Perl: perl -pe 's/(four score and seven years ago|all your base are belong to us|the beat goes on and I\x27m so wrong)/ "█" x length($1) /ge' file (您sed可能有一个-Eor-r选项可以让您避免使用反斜杠,以生成更像 Perl 的正则表达式。Perl 的正则表达式工具比 的那些复杂得多,sed因此如果您切换到Perl,以及用于编写循环、算术等的可读性更强的语言。也许还请注意 Perl 如何让我编写\x27文字单引号,因此我不必胡乱使用 shell 的引用机制来嵌入单引号字符串中的文字单引号。) Best Answer Kamil Maciorowski 2022-06-11T01:56:36+08:002022-06-11T01:56:36+08:00 假设您的文本不包含 ASCII 字符0x02和0x03,则: sed ' s/pattern/\x02\0\x03/g :loop s/\x02[^\x03]/█\x02/g t loop s/\x02\x03//g ' 我使用的字符分别是 STX(文本开头)和 ETX(文本结尾)。如今,它们很少在文本中使用。这使它们成为临时标记的不错选择。 该解决方案首先包含与 STX 和 ETX 模式匹配的每个片段。接下来它循环,将每个 STX 移向行尾,直到遇到 ETX。每一个这样的举动都会导致█出现。当每个 STX 遇到其对应的 ETX 时,循环结束,最后所有 STX+ETX 对都被删除。 如果您sed不支持多字节字符,那么您可能会得到█比预期更多的 s。如果与模式匹配的任何内容包含多字节字符(被误解为单字节字符),就会发生这种情况。即使这样,输入编码为 UTF-8,STX 和 ETX 也可以安全使用,因为 UTF-8 中的多字节字符由最高位为 的字节组成1,而 STX 或 ETX 的最高位为0。这意味着如果您sed不支持多字节字符,那么您可能会得到太多█的 s,但没有有效的 UTF-8 文本会因意外被解释为 STX 或 ETX 而干扰(除非它真的是 STX 或 ETX,因此最初的假设)。 我在 Linux UTF-8 语言环境中使用 GNU sed(它确实支持多字节字符)进行了测试。 例子: printf '%s\n' 'This is a test: CaMeL, 12a15, foo.' \ | sed ' s/[[:upper:][:digit:]]*/\x02\0\x03/g :loop s/\x02[^\x03]/█\x02/g t loop s/\x02\x03//g ' 输入是: This is a test: CaMeL, 12a15, foo. 输出应该是: █his is a test: █a█e█, ██a██, foo.
替换每个字符很容易:
如果您的模式更复杂,您可能必须将其拆分。例如,如果您想用三个 █:s 替换三个长度为 3 的单词,以及两个长度为 4 的单词,我将编写两个单独的规则:
如果你有大量不同长度的模式,也许切换到更强大的语言,比如 Perl:
(您
sed
可能有一个-E
or-r
选项可以让您避免使用反斜杠,以生成更像 Perl 的正则表达式。Perl 的正则表达式工具比 的那些复杂得多,sed
因此如果您切换到Perl,以及用于编写循环、算术等的可读性更强的语言。也许还请注意 Perl 如何让我编写\x27
文字单引号,因此我不必胡乱使用 shell 的引用机制来嵌入单引号字符串中的文字单引号。)假设您的文本不包含 ASCII 字符
0x02
和0x03
,则:我使用的字符分别是 STX(文本开头)和 ETX(文本结尾)。如今,它们很少在文本中使用。这使它们成为临时标记的不错选择。
该解决方案首先包含与 STX 和 ETX 模式匹配的每个片段。接下来它循环,将每个 STX 移向行尾,直到遇到 ETX。每一个这样的举动都会导致
█
出现。当每个 STX 遇到其对应的 ETX 时,循环结束,最后所有 STX+ETX 对都被删除。如果您
sed
不支持多字节字符,那么您可能会得到█
比预期更多的 s。如果与模式匹配的任何内容包含多字节字符(被误解为单字节字符),就会发生这种情况。即使这样,输入编码为 UTF-8,STX 和 ETX 也可以安全使用,因为 UTF-8 中的多字节字符由最高位为 的字节组成1
,而 STX 或 ETX 的最高位为0
。这意味着如果您sed
不支持多字节字符,那么您可能会得到太多█
的 s,但没有有效的 UTF-8 文本会因意外被解释为 STX 或 ETX 而干扰(除非它真的是 STX 或 ETX,因此最初的假设)。我在 Linux UTF-8 语言环境中使用 GNU
sed
(它确实支持多字节字符)进行了测试。例子:
输入是:
输出应该是: