如何避免 Sed 改变文件格式?

如何避免 Sed 改变文件格式?

我尝试使用 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_测试

相关内容