Инструмент Unix для вывода первых n символов в кодированном файле UTF-8

Я хочу напечатать первые 1000 символов в файле в кодировке UTF-8. Я знаю, что инструмент head может печатать первые n байтов файла, но он может вырезать символ в середине, так что в конце я получаю искаженный вывод.

Для этого я могу написать программу на awk, но могу ли я узнать, есть ли более простой способ?

PS. Я считаю необоснованным, что голова и хвост не поддерживают кодировку символов (переменная среды LANG), в то время как другие инструменты, такие как cut, wc, sed и awk, поддерживают кодировку символов.

2 ответа

Решение

Не уверен, что это проще, но это мой путь:

cat file | iconv -t UTF-32 | head -c $[1000 *4+4] | iconv -f UTF-32

Это преобразует Unicode в форму с фиксированной шириной, так что 1000 всегда будет представлять целые символы.

Просто чтобы предоставитьawkКак сказал ОП другим сотрудникам Google, давайте проверим 5 гласных с острым ударением :

      printf 'áéíóú' | LC_CTYPE=en_US.UTF-8 awk '{print substr($0,1,3);exit}'

выбирает первые три символа и выводит желаемое:

      áéí

Каждый из этих символов UTF-8 имеет длину 2 байта, мы можем проверить это с помощью:

      printf 'áéíóú' | hd

который дает:

      00000000  c3 a1 c3 a9 c3 ad c3 b3  c3 ba                    |..........|
0000000a

поэтому мы могли бы эквивалентно протестировать это как:

      printf '\xc3\xa1\xc3\xa9\xc3\xad\xc3\xb3\xc3\xba' | LC_CTYPE=en_US.UTF-8 awk '{print substr($0,1,3);exit}'

Если мы используем неправильную локаль, напримерCкоторый обрабатывает каждый байт отдельно:

      printf 'áéíóú' | LC_CTYPE=C awk '{print substr($0,1,3);exit}' | hd

дает первые три байта:

      c3 a1 c3

который отображается на терминале как:

      á

с тех пор какc3это мусор сам по себе.

Не уверен, как это можно сравнить сiconvс точки зрения производительности для огромных входов. Но для мелочей это достаточно хорошо и просто.

Протестировано на Ubuntu 21.04.

Другие вопросы по тегам