当我sed
像这样运行并打印到控制台时,一切都很好:
sed '/Q/{
s/Q//g
r /Users/ericbrotto/Desktop/question.txt
}' Commision.txt
但是当我这样做并输出 ta 文件时:
sed '/Q/{
s/Q//g
r /Users/ericbrotto/Desktop/question.txt
}' Commision.txt > newFile
...我的新字符串(在之前的输出中被正确替换的字符串)现在读取为一堆亚洲(我相信普通话)字符。
有任何想法吗?
这是一个后续问题我之前提出的问题。
答案1
我之前注意到,如果你采用 ASCII 编码的文本(或者等效地,UTF-8 编码的 ASCII 文本)并将其解码为 UTF-16,你经常会得到“中文字符”(不同的字符取决于你是否将其解码为 UTF- 16BE 或 UTF-16LE)。基于此,我认为您正在处理混合编码。我的猜测是,它Commision.txt
被编码为 UTF-16BE 或 UTF-16LE,即question.txt
纯 ASCII(或 UTF-8 编码的 ASCII),并且最终newFile
会成为两个文件的编码的无效组合。
如果您在两个文件中使用相同的编码,事情应该会更好;可能 UTF-8 效果最好。如果您需要最终输出采用其他编码,那么您可以使用图标对其进行转换 ( iconv -f UTF-8 -t UTF-16BE <newFile >newfile.utf16be.txt
)。
实际上,ASCII 字符的 UTF-16 编码与 ASCII 编码相同,但在每个 ASCII 字符之间插入了额外的 NUL 字符,并且在整个字符之前或之后再插入一个 NUL(取决于 UTF-16 编码的字节顺序) 。这意味着当直接在 UTF-8 终端上查看时(即“打印到控制台”),编码为 UTF-8 或 UTF-16 的 ASCII 文本将看起来“正常”。
只要文件内容保持独立,任何编码检测查看环境(例如编辑器)都可能正确检测编码(或者至少选择一个足够接近的编码,考虑到 UTF-8 和许多单字节编码是相同的)在 ASCII 范围内)。
但是你有sed将文件混合在一起。很遗憾,sed不够“智能”,无法意识到它正在使用两种不同的文本编码处理文件。您最终会得到(根据我的猜测)一个主要是 UTF-16 编码的文件(来自) ,中间Commision.txt
有一个 UTF-8 编码部分(来自)(或者您放置的任何位置)。如果完全解码为 UTF-8,结果可能无效,但如果完全解码为 UTF-16,结果可能有效(尽管 UTF-8 数据所在的位置有一些意外内容)。question.txt
Q
这是一个例子:
Commision.txt
是 UTF-16BE 编码的 ASCII(带有 BOM)。
% xxd Commision.txt
0000000: feff 0046 0069 0072 0073 0074 0020 006c ...F.i.r.s.t. .l
0000010: 0069 006e 0065 000a 004c 0069 006e 0065 .i.n.e...L.i.n.e
0000020: 0020 0077 0069 0074 0068 0020 0061 0020 . .w.i.t.h. .a.
0000030: 0075 0063 0020 0027 0071 0027 003a 0020 .u.c. .'.q.'.:.
0000040: 0028 0051 0029 000a 004c 0061 0073 0074 .(.Q.)...L.a.s.t
0000050: 0020 006c 0069 006e 0065 000a . .l.i.n.e..
question.txt
是 ASCII(或 UTF-8 编码的 ASCII)。
% xxd question.txt
0000000: 5768 6174 2069 7320 7468 6520 6169 722d What is the air-
0000010: 7370 6565 6420 7665 6c6f 6369 7479 206f speed velocity o
0000020: 6620 616e 2075 6e6c 6164 656e 2073 7761 f an unladen swa
0000030: 6c6c 6f77 3f0a llow?.
我将它们与sed。
% sed '/Q/{
s/Q//g
r question.txt
}' Commision.txt >newFile
newFile
是一个烂摊子。
sed删除了Q
单个字节 ( 51
) 而不是其两字节 UTF-16 表示形式 ( 00 51
)。
这会破坏文件其余部分的两字节对齐,给出奇数而不是偶数的整个长度,并引入 UTF-16 NULL ( 0000
)。
% xxd newFile
0000000: feff 0046 0069 0072 0073 0074 0020 006c ...F.i.r.s.t. .l
0000010: 0069 006e 0065 000a 004c 0069 006e 0065 .i.n.e...L.i.n.e
0000020: 0020 0077 0069 0074 0068 0020 0061 0020 . .w.i.t.h. .a.
0000030: 0075 0063 0020 0027 0071 0027 003a 0020 .u.c. .'.q.'.:.
0000040: 0028 0000 2900 0a57 6861 7420 6973 2074 .(..)..What is t
0000050: 6865 2061 6972 2d73 7065 6564 2076 656c he air-speed vel
0000060: 6f63 6974 7920 6f66 2061 6e20 756e 6c61 ocity of an unla
0000070: 6465 6e20 7377 616c 6c6f 773f 0a00 4c00 den swallow?..L.
0000080: 6100 7300 7400 2000 6c00 6900 6e00 6500 a.s.t. .l.i.n.e.
0000090: 0a .
尽管一团糟,但在我的 UTF-8 终端中看起来还不错。
% cat newFile
First line
Line with a uc 'q': ()
What is the air-speed velocity of an unladen swallow?
Last line
然而,当我在 Vim 中加载它时,事情显然不对劲(实际上在左括号后面有一个 NUL,但它的存在导致这篇文章被截断)。 Vim 警告“第 2 行出现转换错误”。
First line
Line with a uc 'q': (⤀桡琠楳⁴桥楲灥敤⁶敬潣楴礠潦渠畮污摥渠獷慬汯眿䰀愀猀琀 氀椀渀攀
如果我删除其中的问号question.txt
(再次给出偶数个字节)并重新生成newFile
,那么我会“返回”最后一行(尽管它粘在第二行的末尾)并避免来自 Vim 的转换警告。
First line
Line with a uc 'q': (⤀桡琠楳⁴桥楲灥敤⁶敬潣楴礠潦渠畮污摥渠獷慬汯眊Last line