Метка порядка байтов ( BOM ) — это особый случай использования специального кода символа Unicode , U+FEFF ZERO WIDTH NO-BREAK SPACE , появление которого в качестве магического числа в начале текстового потока может сигнализировать программе, считывающей текст, о нескольких вещах: [1]
Использование BOM необязательно. Его наличие мешает использованию UTF-8 программным обеспечением, которое не ожидает не- ASCII байты в начале файла, но которое могло бы иначе обрабатывать текстовый поток.
Unicode может быть закодирован в единицах 8-битных, 16-битных или 32-битных целых чисел. Для 16- и 32-битных представлений компьютер, получающий текст из произвольных источников, должен знать, в каком порядке байтов закодированы целые числа. BOM кодируется по той же схеме, что и остальная часть документа, и становится несимвольной кодовой точкой Unicode, если ее байты поменять местами. Следовательно, процесс, получающий доступ к тексту, может проверить эти первые несколько байтов, чтобы определить порядок байтов, не требуя какого-либо контракта или метаданных вне самого текстового потока. Обычно принимающий компьютер при необходимости меняет байты на свой собственный порядок байтов и больше не нуждается в BOM для обработки.
Последовательность байтов BOM различается в зависимости от кодировки Unicode (включая те, которые не входят в стандарт Unicode, например UTF-7 , см. таблицу ниже), и ни одна из последовательностей, скорее всего, не появится в начале текстовых потоков, хранящихся в других кодировках. Поэтому размещение закодированного BOM в начале текстового потока может указывать на то, что текст находится в Unicode, и идентифицировать используемую схему кодирования. Такое использование BOM называется «подписью Unicode». [2]
BOM — это просто кодовая точка Unicode U+FEFF ZERO WIDTH NO-BREAK SPACE
, закодированная в текущей кодировке. Текстовый файл, начинающийся с байтов, FE FF
предполагает, что файл закодирован в big-endian UTF-16.
Имя ZWNBSP следует использовать, если BOM появляется в середине потока данных. Unicode говорит, что его следует интерпретировать как обычную кодовую точку (а именно, слово joiner ), а не как BOM. Начиная с Unicode 3.2, это использование было отменено в пользу . [1]U+2060 WORD JOINER
Имя Unicode 1.0 для этой кодовой точки также BYTE ORDER MARK
[3]
Представление BOM в кодировке UTF-8 представляет собой ( шестнадцатеричную ) последовательность байтов EF BB BF
.
Стандарт Unicode допускает BOM в UTF-8 , [4] но не требует и не рекомендует его использовать. [5] UTF-8 всегда имеет один и тот же порядок байтов, [6] поэтому его единственное использование в UTF-8 — это сигнализировать в начале, что текстовый поток закодирован в UTF-8 или что он был преобразован в UTF-8 из потока, который содержал необязательный BOM. Стандарт также не рекомендует удалять BOM, когда он там есть, чтобы циклический обмен между кодировками не терял информацию, и чтобы код, который на него полагается, продолжал работать. [7] [8] IETF рекомендует, что если протокол либо (a) всегда использует UTF-8, либо (b) имеет какой-то другой способ указать, какая кодировка используется, то он «СЛЕДУЕТ запретить использование U+FEFF в качестве подписи». [9] Примером несоблюдения этой рекомендации является протокол IETF Syslog , который требует, чтобы текст был в UTF-8, а также требует BOM. [10]
Неиспользование BOM позволяет тексту быть обратно совместимым с программным обеспечением, разработанным для расширенного ASCII . Например, многие языки программирования допускают не- ASCII байты в строковых литералах , но не в начале файла.
BOM не нужен для определения кодировки UTF-8. [ необходима цитата ] UTF-8 — разреженная кодировка: большая часть возможных комбинаций байтов не приводит к допустимому тексту UTF-8. Двоичные данные и текст в любой другой кодировке, вероятно, будут содержать последовательности байтов, которые недопустимы как UTF-8, поэтому наличие таких недопустимых последовательностей указывает на то, что файл не является UTF-8, в то время как отсутствие недопустимых последовательностей является очень сильным указанием на то, что текст является UTF-8. Практически единственным исключением является текст, содержащий только байты диапазона ASCII, поскольку это может быть не-ASCII 7-битная кодировка, но это маловероятно в любых современных данных, и даже в этом случае отличие от ASCII незначительно (например, изменение '\' на '¥').
Компиляторы Microsoft [11] и интерпретаторы, а также многие части программного обеспечения в Microsoft Windows, такие как Notepad (до Windows 10 Build 1903 [12] ), рассматривают BOM как обязательное магическое число , а не используют эвристики. Эти инструменты добавляют BOM при сохранении текста в формате UTF-8 и не могут интерпретировать UTF-8, если BOM отсутствует или файл не содержит только ASCII. Windows PowerShell (до 5.1) добавит BOM при сохранении XML-документов UTF-8. Однако PowerShell Core 6 добавил -Encoding
переключатель в некоторые командлеты под названием utf8NoBOM, чтобы документ можно было сохранить без BOM. Google Docs также добавляет BOM при преобразовании документа в обычный текстовый файл для загрузки.
В UTF-16 BOM ( U+FEFF
) может быть помещен в качестве первых байтов файла или потока символов для указания порядка байтов всех 16-битных кодовых единиц файла или потока. Если будет сделана попытка прочитать этот поток с неправильным порядком байтов, байты будут переставлены, таким образом доставляя символ U+FFFE
, который определяется Unicode как « несимвол », который никогда не должен появляться в тексте.
FE FF
FF FE
Для зарегистрированных IANA наборов символов UTF-16BE и UTF-16LE не следует использовать метку порядка байтов, поскольку названия этих наборов символов уже определяют порядок байтов.
Если BOM отсутствует, можно угадать, является ли текст UTF-16 и его порядок байтов, выполнив поиск символов ASCII (т. е. байт 0, смежный с байтом в диапазоне 0x20-0x7E, а также 0x0A и 0x0D для CR и LF). Большое число (т. е. намного больше случайного) в том же порядке является очень хорошим признаком UTF-16, а то, находится ли 0 в четном или нечетном байте, указывает на порядок байтов. Однако это может привести как к ложным положительным, так и к ложным отрицательным результатам.
Пункт D98 соответствия (раздел 3.10) стандарта Unicode гласит: «Схема кодирования UTF-16 может начинаться с BOM или нет. Однако, когда BOM отсутствует и отсутствует протокол более высокого уровня, порядок байтов схемы кодирования UTF-16 — big-endian». Вопрос о том, действует ли протокол более высокого уровня, открыт для интерпретации. Например, файлы, локальные для компьютера, для которого собственный порядок байтов — little-endian, можно считать неявно закодированными как UTF-16LE. Поэтому презумпция big-endian широко игнорируется. Стандарт кодирования W3C / WHATWG, используемый в HTML5, указывает, что содержимое, помеченное как «utf-16» или «utf-16le», должно интерпретироваться как little-endian «для работы с развернутым содержимым». [13] Однако, если присутствует метка порядка байтов, то этот BOM следует рассматривать как «более авторитетный, чем что-либо еще». [14]
Хотя BOM может использоваться с UTF-32 , эта кодировка редко используется для передачи. В противном случае применяются те же правила, что и для UTF-16 .
BOM для little-endian UTF-32 — это тот же шаблон, что и little-endian UTF-16 BOM, за которым следует символ UTF-16 NUL, необычный пример BOM, являющегося одним и тем же шаблоном в двух разных кодировках. Программистам, использующим BOM для определения кодировки, придется решить, какой из вариантов более вероятен: UTF-32 или UTF-16 с первым символом NUL.
В этой таблице показано, как BOM представляется в виде последовательности байтов в различных кодировках и как эти последовательности могут отображаться в текстовом редакторе, который интерпретирует каждый байт как устаревшую кодировку ( Windows-1252 и обозначение курсора для элементов управления C0 ):
38
, 39
, 2B
, или 2F
(ASCII 8
, 9
, +
или /
), в зависимости от того, какой символ следует дальше.U+FEFF
, блок, к которому принадлежит кодовая точка2-4. Семь схем кодирования Unicode
BOM не является ни обязательным, ни рекомендуемым для UTF-8, но может встречаться в контекстах, где данные UTF-8 преобразуются из других кодировок, использующих BOM, или где BOM используется в качестве подписи UTF-8
, поскольку исходный код C++ был закодирован как UTF-8 без BOM (как это обычно бывает в Linux), компилятор Visual C++ ошибочно предположил, что исходный код был закодирован как Windows ANSI.