Я пытался использовать файл 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 ответ1

1

Проблема в том, что механизм регулярного выражения sed не видит ни ваш входной файл, ни ваш […] совпадение в виде списка символов Unicode; вместо этого он видит каждый из них как несколько независимых байтов. Например, он видит как три байта \xe2 \x80 \xa2 и пытается сопоставить каждый из них в отдельности с [ \xe2 \x80 \x98 \xe2 \x80 \x99 \x22 \xe2 \x80 ... ] .

Таким образом, в примере, который вы показали в своем посте, регулярное выражение только сопоставляет и удаляет последний байт каждого символа пунктуации, но оставляет два других по-прежнему там. Вот что дает вам неверный (не UTF-8) выходной файл.

С помощью GNU sed (протестировано на 4.5) этого можно избежать, если убедиться, что языковой стандарт системы (переменные среды $ LANG или хотя бы $ LC_CTYPE) установлен в совместимый с UTF-8 языковой стандарт. Например:

$ export LANG='C'
$ echo '‘test’ “test”' | sed 's/[“”•]/X/g'
XX�testXX� XXXtestXXX
$ echo '•_test' | sed 's/[•‡]_/X_/'
��X_test

$ export LANG='en_US.UTF-8'
$ echo '‘test’ “test”' | sed 's/[“”•]/X/g'
‘test’ XtestX
$ echo '•_test' | sed 's/[•‡]_/X_/'
X_test

(Язык локали не имеет значения. Подойдет любая локаль UTF-8.)

Если это не работает для вас, полностью избегайте […] и используйте \(…\|…\|…\) (или (…|…|…) в sed -r), который является многосимвольной альтернативой и будет работать независимо от того, как эти символы в конечном итоге интерпретируются.

$ export LANG='C'
$ echo '‘test’ “test”' | sed 's/\(“\|”\|•\)/X/g'
‘test’ XtestX
$ echo '•_test' | sed 's/\(•\|‡\)_/X_/'
X_test

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .