折叠的 unicode 安全替代方案

折叠的 unicode 安全替代方案

我习惯fold -w 3将一行分成多个 3 个字符长的行,但是对于 GNU 实现,它似乎不适用于具有多字节字符的文本。

我怎样才能实现上述目标sed

我已经想出了,sed -r 's/^(.{0,3})(.*)/\1\n\2/g'但这只能进行一次替换:

echo "111222333444555666" | sed -r 's/^(.{0,3})(.*)/\1\n\2/g' 
111
222333444555666

其他示例:

echo "ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ" | sed -r 's/^(.{0,3})(.*)/\1\n\2/g' 
ĄĄĄ
ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ

以及fold它的腐败行为:

echo "ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ" | fold -w 3                         
Ą�
�Ą
Ą�
�Ą
Ą�

答案1

短的grep方法:

echo "ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ" | grep -Eo '.{1,3}'
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄ

仅保留 3 个字符的序列:... | grep -Eo '.{3}'

答案2

请注意,问题不在于 Unicode 字符集,而在于使用 2 个或更多字节编码的字符(以及宽度不是一个单元格的字符)。

UTF-8 是 Unicode 的一种编码,其中 U+0080 至 U+10FFFFF 的字符被编码在 2 个或更多字节上。Unicode 字符 U+0000 至 U+007F 与 ASCII 中的字符相同,并且在 UTF-8 中被编码在单个字节上(与 ASCII 中的字符相同),因此在这里不是问题。

Unicode 字符集还有其他编码(例如 iso8859-1,单字节但仅限于字符 U+0000 到 U+00FF,或 GB18030,多字节),还有其他多字节的非 Unicode 字符集编码。

您可以使用该命令了解您的语言环境中使用的字符编码locale charmap

目前, GNU 实现fold只能正确处理单字节字符。大多数fold其他系统不存在这个问题。许多甚至可以处理零或双倍显示宽度的字符。

自 2010 年起,busybox 实现fold就支持 UTF-8(但不支持其他多字节字符映射)。

  • 在 FreeBSD 或 Solaris 上:

      $ echo $'a\u0301bcde' | fold -w3
      ábc
      de
    
  • 与 busybox 折叠:

      $ echo $'a\u0301bcde' | busybox fold -w3
      áb
      cde
    
  • 使用 GNU 折叠:

      $ echo $'a\u0301bcde' | fold -w3
      á
      bcd
      e
    

U+0301 是一种组合锐音。它具有空宽度,并且在 UTF-8 中以 2 个字节 (0xcc 0x81) 进行编码。因此,á( $'a\u0301') 是一个宽度为 1 的字素簇,由 3 个字节编码的 2 个字符组成,因此有 3 种不同的行为,其中最正确的是 FreeBSD/Solaris 的行为。

grep使用带有 PCRE 支持、UTF-8 语言环境和 UTF-8 输入构建的GNU :

grep -Po '\X{1,3}'

在输入的每一行上输出o1 到 3(尽可能多)的所有序列 eX倾向于字素簇,对于上述将标记与单宽字符组合的情况,可能会给您更好的结果。

如果存在双角字符或不与单角字符组合的零字符,或者存在 TAB、CR、BS 等控制字符,则无济于事。

答案3

使用 sed:

$ echo "ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ" | sed 's/.../&\n/g'
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄ

或者更通用的解决方案(更容易定义字符数):

sed    's/.\{3\}/&\n/g'             # Using BRE (basic) syntax
sed -E 's/.{3}/&\n/g'               # Using ERE (extended) syntax.

答案4

只因为...

$ echo "ĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄĄ" | gawk '{$1=$1} 1' FPAT=".{,3}" OFS="\n"
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄĄ
ĄĄ

相关内容