我尝试使用 sed 文件预处理文件,但 sed 的输出似乎改变了格式。我该如何避免这种情况?
file A.txt
A.txt UTF-8 Unicode English text, with very long lines
sed -f process.sed < A.txt > B.txt
head -2 process.sed
#!/bin/sed -f
s/[‘’"“”•·・、。《》™®\.★☆]\\[a-z\-]\+ //g
file B.txt
Non-ISO extended-ASCII English text, with very long lines, with LF, NEL line terminators
因为B.txt不是UTF-8编码,所以我无法进行以下处理。
vim B.txt
è·¯æ<98><93>æ<96>¯ Âç½<97>å¾·é<87><8c>æ ¼æ<96>¯ //è·¯æ<98><93>æ<96>¯Â·ç½<97>å¾·é<87><8c>æ ¼æ<96>¯ ]
答案1
问题在于 sed 的正则表达式引擎不会将您的输入文件或[…]
匹配项视为 Unicode 字符列表;相反,它会将每个字符视为多个独立字节。例如,它会将其视为•
三个字节\xe2 \x80 \xa2
,并尝试将每个字节分别与 进行匹配[ \xe2 \x80 \x98 \xe2 \x80 \x99 \x22 \xe2 \x80 ... ]
。
因此,在您帖子中显示的示例中,正则表达式仅匹配并删除每个标点符号的最后一个字节,但其他 2 个字节仍保留在那里。这就是导致您得到无效(非 UTF-8)输出文件的原因。
使用 GNU sed(在 4.5 上测试),可以通过确保系统区域设置($LANG 或至少 $LC_CTYPE 环境变量)设置为兼容 UTF-8 的区域设置。例如:
$ 导出 LANG='C' $ echo ''测试' “测试”' | sed 's/[“”•]/X/g' XX�测试XX� XXX测试XXX $ echo '•_test' | sed 's/[•‡]_/X_/' ��X_测试 $ 导出 LANG='en_US.UTF-8' $ echo ''测试' “测试”' | sed 's/[“”•]/X/g' ‘测试’ XtestX $ echo '•_test' | sed 's/[•‡]_/X_/' X_测试
(区域语言不重要。任何UTF-8 语言环境可以工作。)
如果这对您不起作用,请[…]
完全避免并使用\(…\|…\|…\)
(或(…|…|…)
在 sed -r 中),这是一个多字符替代方法,无论这些字符最终如何解释,它都会起作用。
$ 导出 LANG='C' $ echo ''测试' “测试”' | sed 's/\(“\|”\|•\)/X/g' ‘测试’ XtestX $ echo '•_test' | sed 's/\(•\|‡\)_/X_/' X_测试