Sed

折疊的 unicode 安全替代品

  • March 1, 2022

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                         
Ą�
�Ą
Ą�
�Ą
Ą�

簡短**grep**的方法:

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

僅保留 3 字元序列:... | grep -Eo '.{3}'

請注意,問題不在於 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}'

o在輸入的每一行上輸出1 到 3 個(盡可能多)的所有序列,X可能會給你更好的結果,比如上面的情況,你將標記與單寬字元組合在一起。

如果有雙角字元或零與未與單角字元組合的字元或有 TAB、CR、BS 等控製字元,則無濟於事。

引用自:https://unix.stackexchange.com/questions/454044