$ locale charmap
UTF-8
В моей нынешней среде набор символов - это UTF-8, то есть символы кодируются от 1 до 4 байтов на символ (хотя, поскольку исходное определение допустимого кода символов UTF-8 указывает на 0x7fffffff, большинство инструментов распознает UTF- 8-байтовые последовательности до 6 байт).
В этом наборе символов доступны все символы из Unicode, например, a a
кодируется как значение байта 65, a 乕
как 3 байта 228 185 149 и é
как двухбайтовая последовательность 195 169.
$ printf 乕 | wc -mc
1 3
$ printf a | wc -mc
1 1
В настоящее время:
$ export fr_FR.iso885915@euro
$ locale charmap
ISO-8859-15
Я изменил свое окружение, в котором теперь используется набор символов ISO-8859-15 (другие вещи, такие как язык, символ валюты, формат даты, также были изменены, а коллекция этих региональных настроек называется локалью ). Мне нужно запустить новый эмулятор терминала в этой среде, чтобы адаптировать рендеринг символов к новой локали.
ISO-8859-15 является однобайтовым набором символов, что означает, что он имеет только 256 символов (фактически даже меньше, чем это фактически покрыто). Этот конкретный набор символов используется для языков Западной Европы, поскольку он охватывает большинство ее языков (и символ евро).
Он имеет a
символ со значением байта 65, как в UTF-8 или ASCII, он также имеет é
символ (как обычно используется на французском или испанском языке, например), но со значением байта 233 у него нет символа 乕.
В такой среде wc -c
и wc -m
всегда будет давать один и тот же результат.
В Ubuntu, как и в большинстве современных Unix-подобных систем, по умолчанию обычно используется UTF-8, поскольку это единственный поддерживаемый набор символов (и кодировка), который охватывает весь диапазон Unicode.
Существуют другие многобайтовые кодировки символов, но они не так хорошо поддерживаются в Ubuntu, и вы должны пройти через обручи, чтобы иметь возможность сгенерировать локаль с ними, и если вы это сделаете, вы обнаружите, что многие вещи не работать должным образом.
Таким образом, в Ubuntu наборы символов являются однобайтовыми или UTF-8.
Теперь еще несколько заметок:
В UTF-8 не все последовательности байтов образуют допустимые символы. Например, все символы UTF-8, которые не являются символами ASCII, формируются из байтов, для которых все установлены 8-м битами, но где только у первого установлен 7-й бит.
Если у вас есть последовательность байтов с установленным 8-м битом, ни у одного из которых не установлен 7-й бит, то это не может быть преобразовано в символ. И вот тогда у вас начинаются проблемы и несоответствия, так как программное обеспечение не знает, что с ними делать. Например:
$ printf '\200\200\200' | wc -mc
0 3
$ printf '\200\200\200' | grep -q . || echo no
no
wc
и не grep
найти там никакого персонажа, кроме:
$ x=$'\200\200\200' bash -c 'echo "${#x}"'
3
bash
находит 3. Когда он не может отобразить последовательность байтов на символ, он считает каждый байт символом.
Это может стать еще более сложным, поскольку в Unicode есть кодовые точки, которые являются недопустимыми в качестве символов, а некоторые не являются символами , и в зависимости от инструмента их кодировка UTF-8 может или не может рассматриваться как символ.
Еще одна вещь, которую следует принять во внимание, - это разница между характером и графическим символом и то, как они отображаются.
$ printf 'e\u301\u20dd\n'
é⃝
$ printf 'e\u301\u20dd' | wc -mc
3 6
Там мы кодируем 3 символа как 6 байтов, отображаемых как один граф, потому что у нас есть 3 символа, объединенные вместе (один базовый символ, объединяющий острый акцент и объединяющий окружающий круг).
В реализации GNU, wc
как в Ubuntu, есть -L
переключатель, показывающий ширину отображения самой широкой строки на входе:
$ printf 'e\u301\u20dd\n' | wc -L
1
Вы также обнаружите, что некоторые символы занимают 2 ячейки в расчете ширины, как наш 乕
персонаж сверху:
$ echo 乕 | wc -L
2
В заключение: в более диком слове байт, символ и графем не обязательно совпадают.