Нельзя предполагать что все используют utf 8

Время на прочтение

Нельзя предполагать что все используют utf 8

Как вычислять кодировку при помощи статистики

Люди говорят на бесчисленном количестве разных языков. Эти языки не только несовместимы между собой, но и представляют огромную трудность при транспиляции в среде исполнения. К сожалению, все попытки стандартизации провалились.

По крайней мере, в таком положении вещей есть, кого винить: Бога. Ведь именно он вынудил человечество говорить на разных языках из-за древнего спора о строительстве объекта недвижимости.

Однако человечество может винить себя за то, что сложности в общении испытывают компьютеры.

И одна из самых больших проблем одновременно является самой простой: компьютеры не договорились о том, как записывать буквы двоичным кодом.

Вероятно, основная часть кода определения кодировок работает на принципах, заложенных Netscape в начале 2000-х. Статья с описанием этого подхода есть в архиве Mozilla.

У меня есть чёткое впечатление, что автоматическое определение кодировки текста — это частный случай закона Постела: «будь консервативным в том, что делаешь, будь либерален в том, что принимаешь от других». Я всегда воспринимал закон Постела как что-то истинное, но сейчас у меня возникает всё больше сомнений. Возможно, механизм автоматического определения кодировки в моей базе данных csvbase стоит сделать частью пользовательского интерфейса, а не заранее выбранным пунктом выпадающего списка.

Telegram-канал со скидками, розыгрышами призов и новостями IT 💻

Нельзя предполагать что все используют utf 8

Illegal Bytes sequence

Nair's user avatar

Не работает поиск с русским языком SQL

Ivam's user avatar

При подключении по SSH с помощью Windows PowerShell с Windows 11 к Mac OS X кириллица выводится знаками вопроса

Alexey Trukhanov's user avatar

Ошибка в кодировке при прочтении pdf файла

tupoy's user avatar

Как записать в .bat файл команду с русскими символами?

Nair's user avatar

Как конвертировать путь в wstring?

Nair's user avatar

Декодирование json на Python

Elena's user avatar

Как починить кодировки в Visual Studio?

Русский текст выводит непонятными символами, хотя раньше все исправно работало. Visual Studio даже было переустановлено, проблема не решилась. Что можно сделать??

sirena sirenevaya's user avatar

Кодировка java.util.Scanner

Polen Unger's user avatar

Изменение всех заглавных букв файла строчными, вывод количества символов текста из файла

Malekis's user avatar

Вместо русских символов “???”

MeemMc Music's user avatar

Конвертация между utf8 и cp1251 с сохранением результата

как сменить кодировку utf8 на cp1251 и обратно, чтобы буква ‘ю’ так и осталась буковой ‘ю’? под буквой подразумевал любой символ русской раскладки

Fynjisx's user avatar

При удалении введенных ранее русских символов в input() пояляется аномальное поведение в методах socket.send() и fd.read()

Dart5678899765444's user avatar

Проблема с кодировкой в скрипте PHP

Алексей Петров's user avatar

Совместная разработка проекта на python на Windows и MacOS проблемы кодировки

Chertan Milanii's user avatar

Начало: «С++ в Windows 10, VS Code: кодировка консоли при отладке».

При изучении языка программирования C++ по сайту-учебнику «LearnCpp.com» я пишу маленькие учебные программы, которые предназначены для работы в консоли. В рамках учебы по этому учебнику предполагается, что создаваемый исходный код является кроссплатформенным (может быть без проблем скомпилирован в исполняемый файл на разных операционных системах).

Исходный код я храню в кодировке UTF-8. Для вывода текста в консоль я использую «узкие» символы типа char через std::cout. Я вывожу тексты с буквами английского и русского алфавитов, китайских иероглифов, эмодзи и так далее.

Я работаю на компьютере под управлением операционной системы «Windows 10», а также работаю с операционной системой «Ubuntu» (один из дистрибутивов «Linux») из «Windows 10» через подсистему «WSL 2». Я отказался от использования функций Windows API для переключения кодовой страницы в консоли, так как этот же исходный код использую и для компиляции в операционной системе «Ubuntu» (в ней функции Windows API недоступны).

:/>  Сколько нужно термопасты для процессора и почему не нужно менять термопасту на видеокарте и процессоре по моему мнению

Переключение кодовой страницы в операционной системе «Windows 10» при работе с программами в консоли я произвожу вручную (команда chcp 65001) в программе-оболочке «cmd.exe» и через профиль в программе-оболочке «PowerShell». В операционной системе «Ubuntu» переключение кодовой страницы не требуется, там по умолчанию в консоли (я использую программу-оболочку «bash») используется кодировка UTF-8.

Вроде всё в порядке, однако, есть проблема при отладке. Для написания исходного кода и отладки программ я использую редактор кода «VS Code» и/или интегрированную среду разработки «Visual Studio Community 2022». При запуске отладки (отладку я произвожу в операционной системе «Windows 10») эти инструменты запускают свои собственные экземпляры программ-оболочек, и сразу непонятно, как в этих экземплярах программ-оболочек переключить кодовую страницу на нужную (инструменты разработки не дают возможности ввести в открываемые экземпляры программ-оболочек какие-либо предварительные команды).

В редакторе кода «VS Code» я смог решить эту проблему (см. мой предыдущий пост по этой теме). А вот в среде «Visual Studio» долго не мог справиться с этой проблемой. Написал вопрос на веб-сервисе «Stack Overflow» и там мне через некоторое время смогли подсказать рабочий способ решения:

Способ решения проблемы

Казалось бы, если редактор кода «VS Code» (Visual Studio Code) изначально вобрал в себя некоторые важные элементы среды «Visual Studio» (поэтому у них похожие названия), то его разработка должна несколько отставать от его «родителя» (на самом деле, эти инструменты построены по совершенно разным принципам и существуют для разных целевых аудиторий). Но на деле выходит, что в некоторых вещах редактор «VS Code» опережает своего массивного «коллегу».

Например, в редакторе «VS Code» можно настроить вывод в консоль при отладке минимум тремя разными способами (я описывал их подробно по ссылке, приведенной в начале данного поста): во внешнюю консоль (в отдельном окне) с программой-оболочкой «cmd.exe», во внутренний терминал во вкладку с программой-оболочкой «PowerShell» и во внутренний терминал во вкладку консоли отладки. В среде «Visual Studio Community 2022», насколько я понимаю, по умолчанию есть только один способ: во внешнюю консоль (в отдельном окне) с программой-оболочкой «cmd.exe».

1. Установка расширения

По подсказке из вышеприведенного вопроса на веб-сервисе «Stack Overflow» я установил для среды «Visual Studio Community 2022» расширение «Microsoft Child Process Debugging Power Tool 2022».

Загрузка расширения и его установка не начинаются сразу, а ставятся в план, который будет запущен при закрытии окна среды «Visual Studio Community 2022». Я закрыл окно среды и загрузка запустилась. После загрузки расширение установилось и я снова запустил среду.

2. Настройка расширения

После повторного запуска среды я открыл окно «Управление расширениями» и проверил, что установленное расширение оказалось в списке «Установленные». Рядом с названием расширения появились кнопки «Отключить» и «Удалить». Сразу после установки расширение уже включено, но с помощью этих кнопок вы его можете либо временно отключить, либо вообще удалить. Очевидно, что для работы с расширением оно должно быть включенным.

Нельзя предполагать что все используют utf 8

В этой вкладке я только установил флажок «Enable child process debugging» над таблицей и нажал на кнопку «Save» справа над таблицей. После этого я закрыл эту вкладку.

3. Как производить отладку с этим расширением

(3.1) Сначала следует в среде «Visual Studio Community 2022» открыть нужный файл с исходным кодом и установить хотя бы одну точку останова (это можно сделать, установив курсор на нужную строку и нажав клавишу «F9»).

Следует иметь в виду, что при описываемом способе отладки вывод программы в консоль будем производить не стандартным для среды «Visual Studio Community 2022» образом, а в выбранное нами предварительно открытое окно консоли с программой-оболочкой «cmd.exe». Можно использовать обычное окно программы-«эмулятора терминала» «Windows Console», но я предпочитаю использовать программу-«эмулятор терминала» «Windows Terminal».

(3.2) Итак, я запустил программу-«эмулятор терминала» «Windows Terminal» и в ней открыл вкладку с программой-оболочкой «cmd.exe». Для меня это не является каким-то дополнительным действием, я обычно и так всегда это проделываю перед началом работы над проектом. В программе-оболочке «cmd.exe» я выполнил команду chcp 65001, тем самым включив кодовую страницу 65001 (кодировка UTF-8).

:/>  Файл занят другой программой что делать

Нельзя предполагать что все используют utf 8

(3.4) В окне программы-оболочки «cmd.exe» следует запустить отладочную версию исполняемого файла, которая должна находиться в соответствующей подпапке папки проекта. В моем случае это следующий исполняемый файл:

C:\Users\Илья\source\repos\Project1\x64\Debug\Project1.exe

После этого в окне среды «Visual Studio Community 2022» начнется пошаговая отладка и выполнение программы остановится на заданной ранее точке останова. Далее отладку можно производить так же, как и обычно, только вывод программы теперь при отладке направляется в выбранное и предварительно настроенное нами для работы с кодировкой UTF-8 нужное окно.

Вот как это выглядит у меня:

Нельзя предполагать что все используют utf 8

На первый взгляд немного сложновато, конечно. Но быстро привыкаешь. Надеюсь, разработчики среды «Visual Studio Community 2022» в будущем как-то улучшат удобство отладки. Впрочем, я для отладки учебных программ собираюсь в основном использовать редактор «VS Code».

(3.5) После завершения отладки для отключения от процесса следует нажать на кнопку «Остановить отладку» на панели инструментов среды, либо сделать то же самое с помощью сочетания клавиш «Shift+F5».

Если понадобится еще раз запустить отладку, то к процессу «cmd.exe» (если вы еще не закрыли окно с этой программой-оболочкой) можно быстро переподключиться с помощью пункта главного меню «Отладка – Повторно подключиться к процессу» (Shift+Alt+P).

Действительно ли это работает?

Обычно люди не очень любят эвристики, но ответом является «да». Это работает, и на удивление хорошо. И намного лучше, чем просто предположения о том, что текст закодирован UTF-8 (в конечном итоге это и является бенчмарком).

Вероятно, нас не должно удивлять, что статистика работает. Она часто хорошо работает с языками, от первых эффективных спам-фильтров до множества других вещей.

Эвристики тоже важны, потому что люди понимают кодировки неправильно.

Может показаться логичным, что если вы экспортируете лист Excel в файл csv в последней версии MS Excel, то получите UTF-8. Ну, или, возможно, UTF-16. Но вы ошибётесь. По умолчанию, в большинстве конфигураций Excel сохраняет CSV в кодировке Win-1252.

Win-1252 — это однобайтная кодировка, не относящаяся к Unicode. Это расширение ASCII, засовывающее в неиспользованный восьмой бит достаточно большое количество символов для почти каждого европейского языка. Обычный пользователь Excel никогда о ней не слышал, если вообще слышал о кодировках символов. Во многой мудрости много печали.

Определение кодировки при помощи статистики

Существует две базовые стратегии для определения кодировки неразмеченной строки текста.

  1. На уровне байтов
  2. На уровне символов

В большинстве реализаций сначала используется уровень байтов, а при необходимости уровень символов.

▍ Эвристики уровня байтов

На уровне байтов всё довольно просто. Достаточно взглянуть на байты и понять, выглядят ли они похожими на конкретную кодировку символов.

Существуют и другие признаки. Представьте, что вы веб-браузер, и ссылка перенесла пользователя к файлу, два первых байта которого имеют следующий вид:

Если бы это был UTF-16, то эти два байта оказались бы символом ℼ, имеющим название double struck small pi и номер 8508 (U+213C) в Unicode. Часто ли этот символ первым встречается в файле HTML?

Или более вероятно, что это двухсимвольная последовательность <! в кодировке UTF-8? Возможно, следующие байты — это doctype> или стандартный бойлерплейт любого документа HTML?

Ещё одна подсказка — это конкретные байты. Как ни ужасно, UTF-16 имеет две версии: в одной биты записываются обычным образом, в другой — в обратную сторону. Чтобы люди различали эти две версии, в стандарте UTF-16 есть маркер последовательности байтов (byte order mark), который можно поместить перед текстовым потоком, чтобы обозначить используемую версию. Эта пара байтов редко встречается в других кодировках, и практически никогда не бывает в начале, так что они становятся хорошей подсказкой о том, что идёт за ними.

Итак, байты могут дать нам довольно много информации о кодировке. Если вы можете с их помощью однозначно определить UTF-8 или UTF-16, то наша задача выполнена.

▍ Эвристики уровня символов

Сложности возникают с однобайтовыми кодировками, не относящимися к Unicode. Например, сложно отличить Win-1252 от KOI8, ведь для кодирования разных вещей и та, и другая используют обычно пустой первый бит ASCII.

Как же их отличить? Благодаря частотному анализу. Мы смотрим на буквы, которые могли бы присутствовать в документе, например, если это KOI8, и задаёмся вопросом: «Действительно ли это типичное распределение букв для документа на кириллице?».

:/>  Как почистить буфер обмена на компьютере

Вот базовый алгоритм:

  • Исключаем все кодировки, отсечённые предыдущими эвристиками уровня байтов
  • Для каждой оставшейся возможной кодировки X:
    • Парсим входные данные, как будто они были закодированы X
    • Сравниваем частотность символов в строке со значениями в известной таблице частотности
    • Опционально также сравниваем пары букв (например, qu) с известной таблицей частотности
    • Если они достаточно хорошо совпадают, то возвращаем X

  • В противном случае возвращаем ошибку

Часто таким образом можно также определить, на каком языке написан этот документ — именно благодаря этому веб-браузеры открывают диалоговое окно «Перевести эту страницу?».

Как определить, какая кодировка используется?

Некоторые форматы сами задают кодировку, например, JSON обязует применять UTF-8. Это сильно упрощает жизнь — если ты знаешь, что данные записаны в JSON, то они должны быть закодированы в UTF-8.

В других случаях можно передать кодировку отдельно. HTTP позволяет помещать кодировку в заголовок Content-Type:

Content-type: text/html; charset=ISO-8859-1

А у некоторых форматов есть внутренние способы указания кодировки. Например, у некоторых текстовых файлов есть заголовок:

# -*- encoding: utf-16be -*-

Однако это немного сбивает с толку, потому что для того, чтобы найти этот заголовок, нам сначала нужно как-то заранее прочитать файл.

Ну а если у данных нет никаких меток?

Или если метка ошибочна? Как будет показано ниже, встречается такое довольно часто.

Что будет тогда?

Решением будет статистика.

Как записываются буквы двоичным кодом

Возьмём для примера символ латиницы «A». В American Standard Code for Information Interchange, или ASCII, ему назначено число 65. Такая нумерация была унаследована Unicode, только в Unicode число 65 записывается в шестнадцатеричном виде (U+0041). Такую запись называют «элементом кодового пространства» (codepoint).

Здесь всё довольно просто; по крайней мере, в вопросе числа, обозначающего «A», в целом есть консенсус. Но компьютеры не могут просто хранить десятичные числа, они хранят только двоичные.

В самой популярной кодировке символов UTF-8 номер символа 65 («A») записывается так:

Равны единице, или «включены» только второй и последний биты. Второй бит обозначает 64, а последний — 1. В сумме они дают 65. Всё очень просто.

Ещё одна популярная кодировка — это UTF-16, в основном применяемая в мире Windows, Java и
JavaScript. В UTF-16 число 65 записывается следующим образом:

Практически то же самое, только UTF-16 использует под каждый символ два полных байта (как минимум), но не требует дополнительных битов для описания 65, так что второй байт остаётся пустым.

А что там с другими кодировками? Вот лишь некоторые из наиболее популярных:

Все эти кодировки наследуют от букв ASCII, поэтому во всех них A записывается так:

Точно так же, как в UTF-8.

Очень удобно. Именно поэтому базовый западноевропейский алфавит читаем, даже когда остальная часть документа превращается в исковерканный хаос. Многие популярные кодировки (за исключением UTF-16) соответствуют ASCII, по крайней мере, для латиницы.

Пока всё неплохо. Но давайте теперь рассмотрим более сложный символ: знак евро, €. Консорциум Unicode обозначил его числом 8364 (U+20AC).

В UTF-8 число 8364 представляется в следующем виде:

11100010 10000010 10101100

Обратите внимание, что в UTF-8 оно занимает три байта. UTF-8 — это кодировка символов с «переменной длиной»: чем больше число Unicode, тем больше байтов требуется. (На самом деле это справедливо и для UTF-16, но встречается реже.)

Однако в UTF-16 число 8364 кодируется совершенно иначе:

Win-1252 не следует стандарту Unicode. В этой кодировке знак евро имеет номер 128. И кодировка записывает 128 вот так:

То есть лишь один включённый бит равен 128.

И вот здесь начинаются проблемы. Как только мы покидаем спокойные улочки английского алфавита, кодировки быстро становятся хаотичными.

невозможно никак представить в KOI8.

В GB18030 символ € кодируется так:

В Big5 символ € выглядит так:

В Shift JIS это

Абсолютно разные и совершенно несовместимые. Если автоматически предполагать, что используется UTF-8, то мы получим полную чушь.