Character-Encoding
tr 不替換撇號
我想將此文件中的所有撇號轉換為
X
:Bob's book Bob’s book Bob′s book # (Might look the same but actually different)
第一個撇號按預期替換:
$ cat file | tr "'" "X" BobXs book Bob’s book Bob′s book
但是另外兩種撇號,奇怪的事情發生了:
$ cat file | tr "’" "X" Bob's book BobXXXs book BobXX�s book $ cat file | tr "′" "X" Bob's book BobXX�s book BobXXXs book
如何讓它發揮作用?
tr
以字節為單位工作,這意味著它不適用於 UTF-8 等多字節編碼。我知道的唯一解決方案是找到一個tr
支持 Unicode 的版本,或者切換到sed
或其他一些可以進行字元串替換的工具。
對我來說,只要您的作業系統配置為使用 utf-8 程式碼頁, tr 就適用於 ascii 和 utf-8 文件。
這是我的範例 #1(Solaris 11):
$ locale LANG=en_US.UTF-8 LC_CTYPE="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_ALL=
如您所見,作業系統配置為使用 utf-8。我在 utf-8 程式碼頁中創建了這兩個文件:
$ cat file Bob’s Bob′s Bob's $ cat apos ’′'
然後我得到了預期的結果,像這樣替換所有 apos:
$ cat file | tr "$(cat apos)" "xxx" Bobxs Bobxs Bobxs
這是我的範例 #2(Solaris 10):
$ locale LANG= LC_CTYPE="C" LC_NUMERIC="C" LC_TIME="C" LC_COLLATE="C" LC_MONETARY="C" LC_MESSAGES="C" LC_ALL=
在這裡,您可以看到此作業系統配置為處理簡單的 ASCII,而不是 utf-8,因此您可能會遇到使用 tr 處理具有多字節字元的 utf-8 文件的問題。但是有解決方法。只要 tr 命令允許輸入字元的八進製表示,那麼您可以使用八進製表示替換指定字元的所有字節。
在您的情況下,您有:
char hex octal ’ E2 80 99 \342\200\231 ′ E2 80 B2 \342\200\262 ' 27 \47
第一個和第二個 apos 由三個字節表示。第三個是標準ascii(一個字節)。
因此,如果您想替換第一個 apos,您可以使用:
$ cat file | tr "\342\200\231" "\0\0x" Bobxs Bob▒s Bob's
第二:
$ cat file | tr "\342\200\262" "\0\0x" Bob▒s Bobxs Bob's
第三:
$ cat file | tr "\47" "x" Bob’s Bob′s Bobxs
要一次性替換所有內容,您可以使用:
$ cat file | tr "\342\200\231\262\47" "\0\0xxx" Bobxs Bobxs Bobxs
當然它並不完美,只要它會替換文件中所有出現的字節\342、\200、\231、\262,因此包含這些字節的其他多字節字元將被破壞。但是,如果您的文件不包含任何其他多字節字元,它將起作用。