Удаление шестнадцатеричных байтов с помощью sed - нет совпадения

У меня есть текстовый файл с двумя байты не ascii (0xFF и 0xFE):

??58832520.3,ABC
348384,DEF

Гекс для этого файла:

FF FE 35 38 38 33 32 35 32 30 2E 33 2C 41 42 43 0A 33 34 38 33 38 34 2C 44 45 46

По совпадению, FF и FE оказываются ведущими байтами (они существуют во всем моем файле, хотя, по-видимому, всегда в начале line).

Я пытаюсь удалить эти байты с помощью sed, но ничего, что я делаю, кажется, не соответствует им.

$ sed 's/[^a-zA-Z0-9\,]//g' test.csv 
??588325203,ABC
348384,DEF

$ sed 's/[a-zA-Z0-9\,]//g' test.csv 
??.

Основной вопрос: как мне удалить эти байты?
Дополнительный вопрос: два приведенных выше регулярных выражения являются прямыми отрицаниями, поэтому один из них должен логически отфильтровать эти байты, верно? Почему оба этих регулярных выражения совпадают с байтами 0xFF и 0xFE?

Обновление : прямой подход к удалению диапазона шестнадцатеричного байта (предложенный двумя ответами ниже), по-видимому, удаляет первый «правильный» байт из каждую строку и оставляйте байты, от которых я пытаюсь избавиться:

$sed 's/[\x80-\xff]//' test.csv
??8832520.3,ABC
48384,DEF

FF FE 38 38 33 32 35 32 30 2E 33 2C 41 42 43 0A 34 38 33 38 34 2C 44 45 46 0A

Обратите внимание на пропущенные «5» и «3» в начале каждой строки, а новый 0A добавлен в конец файла.

Большое обновление : Эта проблема, похоже, зависит от системы. Проблема наблюдалась в OSX, но предложения (включая мое первоначальное утверждение sed выше) работают, как я ожидаю, в NetBSD.

Решение : Эта та же задача кажется достаточно простой через Perl:

$ perl -pe 's/^\xFF\xFE//' test.csv
58832520.3,ABC
348384,DEF

Однако я Я оставлю этот вопрос открытым, так как это всего лишь обходной путь, и не объясняет, в чем проблема с sed.

7
задан G__ 8 August 2010 в 23:08
поделиться

7 ответов

sed 's/[^ -~]//g'

или, как следует из другого ответа,

sed 's/[\x80-\xff]//g'

См. раздел 3.9 информационных страниц sed. Глава под названием «Побеги».

Отредактируйте для OSX, настройка собственного языка - en_US.UTF-8

try

LANG='' sed 's/[^ -~]//g' myfile

Здесь это работает на машине OSX, я не совсем уверен, почему это не работает в UTF- 8

4
ответ дан 7 December 2019 в 01:14
поделиться

Это приведет к удалению всех строк, которые начинаются с определенных байтов. FF FE

sed -e 's/\xff\xfe//g' hexquestion.txt

Причина, по которой ваши инвертированные регулярные выражения не работают, заключается в том, что [] указывает класс символов. sed предполагает определенный набор символов, вероятно, ascii. Эти символы в вашем файле не являются 7-битными символами ascii, поскольку оба они начинаются с F. sed не знает, как с ними бороться. В приведенном выше решении не используются классы символов, поэтому оно должно быть более переносимым между платформами и наборами символов.

3
ответ дан 7 December 2019 в 01:14
поделиться

Байты FF и FE в начале вашего файла - это так называемая "метка порядка байтов (BOM)". Он может появляться в начале текстовых потоков Unicode, чтобы указать на конечность текста. FF FE указывает на UTF-16 в Little Endian

Вот выдержка из FAQ:

Q: Как мне следует обращаться с BOMами?

A: Вот некоторые рекомендации:

  1. Определенный протокол (например, соглашения Microsoft для .txt файлов) может потребовать использования BOM в определенных потоках данных Unicode, таких как файлы. Когда вам нужно соответствовать такому протоколу, используйте BOM.
  2. Некоторые протоколы допускают необязательные BOM в случае немаркированного текста. В этих случаях,
    • Если известно, что поток текстовых данных является обычным текстом, но неизвестна кодировка, BOM может использоваться в качестве подписи. Если BOM отсутствует, кодировка может быть любой.
    • Если известно, что текстовый поток данных является обычным текстом Unicode (но не известно, в какой кодировке), то в качестве подписи можно использовать BOM. Если BOM нет, то текст следует интерпретировать как big-endian.
  3. Некоторые байт-ориентированные протоколы ожидают ASCII-символы в начале файла. Если в этих протоколах используется UTF-8, следует избегать использования BOM в качестве подписи формы кодирования.
  4. Если точный тип потока данных известен (например, Unicode big-endian или Unicode little-endian), BOM не следует использовать. В частности, когда поток данных объявлен как UTF-16BE, UTF-16LE, UTF-32BE или UTF-32LE, BOM не должен использоваться.

Ссылки

См. также

Похожие вопросы

2
ответ дан 7 December 2019 в 01:14
поделиться

Вы можете получить шестнадцатеричные коды с помощью \ xff \ xfE и ничего не заменить.

0
ответ дан 7 December 2019 в 01:14
поделиться

Чтобы показать, что это не проблема спецификации Unicode, а проблема восьмибитных символов по сравнению с семибитными и привязана к языку, попробуйте следующее:

Показать все байты:

$ printf '123 abc\xff\xfe\x7f\x80' | hexdump -C
00000000  31 32 33 20 61 62 63 ff  fe 7f 80                 |123 abc....|

Попросите sed удалить символы, не являющиеся буквенно-цифровыми в локали пользователя. Обратите внимание, что пробел и 0x7f удалены:

$ printf '123 abc\xff\xfe\x7f\x80'|sed 's/[^[:alnum:]]//g' | hexdump -C
00000000  31 32 33 61 62 63 ff fe  80                       |123abc...|

Сделайте так, чтобы sed удалил символы, которые не являются буквенно-цифровыми в локали C. Обратите внимание, что остается только «123abc»:

$ printf '123 abc\xff\xfe\x7f\x80'|LANG=C sed 's/[^[:alnum:]]//g' | hexdump -C
00000000  31 32 33 61 62 63                                 |123abc|
0
ответ дан 7 December 2019 в 01:14
поделиться

В OS X метка порядка байтов, вероятно, читается как одно слово. Попробуйте sed 's/^\xfffe//g' или sed 's/^\xfeff//g' в зависимости от эндиана.

1
ответ дан 7 December 2019 в 01:14
поделиться

В качестве альтернативы вы можете использовать ed(1):

printf '%s\n' H $'g/[\xff\xfe]/s///g' ',p' | ed -s test.csv

printf '%s\n' H $'g/[\xff\xfe]/s///g' wq | ed -s test.csv  # in-place edit
0
ответ дан 7 December 2019 в 01:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: