바이트 순서 표식

바이트 순서 표시(Byte Order Mark, BOM)는 유니코드 문자 U+FEFF byte order mark로, 매직 넘버로서 문서의 가장 앞에 추가하여 텍스트를 읽는 프로그램에 여러 정보를 전달할 수 있다. 16비트 혹은 32비트 인코딩의 경우, 문서의 바이트 순서 또는 엔디언 문서의 인코딩이 거의 확실히 유니코드임 문서에 사용한 유니코드 문자 인코딩 방식 BOM을 반드시 사용할 필요는 없으며, 사용할 경우 문서의 가장 앞에 등장해야 한다. 유니코드는 8비트, 16비트 혹은 32비트 정수 단위로 인코딩할 수 있다. 16비트 및 32비트 표현의 경우, 알 수 없는 출처로부터 텍스트를 읽는 컴퓨터는 데이터를 어떤 바이트 순서로 인코딩했는지 알아야 한다. BOM은 문서의 나머지 부분과 같은 방식으로 인코딩되며 바이트 순서가 바뀔 경우 비문자인 유니코드 코드 포인트가 되므로, 이 텍스트를 읽는 프로세스는 문서 외적인 정보 없이도 처음 몇 바이트를 검사함으로써 엔디언을 확인할 수 있다. 이후 수신자는 필요할 경우 바이트 순서를 자신의 엔디안에 맞게 바꾸며, 이 이후의 처리에는 더 이상 BOM이 필요하지 않다. BOM의 바이트열은 유니코드 인코딩마다 다르며, 이들이 다른 인코딩으로 저장된 문서의 가장 앞에 등장할 가능성은 적다. 그러므로, 문서의 가장 앞에 인코딩된 BOM을 추가함으로써 텍스트가 유니코드임을 나타내고 그 인코딩 방식을 명시할 수 있다. BOM 문자를 이 방식으로 사용하는 것을 "유니코드 시그니처"라 한다. BOM 문자가 데이터 스트림 중간에 등장할 경우, 유니코드에서는 이를 "폭과 줄 바꿈 없는 공백"(단어 문자 사이에서 줄바꿈을 방지함)로 해석해야 한다고 명시하고 있다. 유니코드 3.2에서는 이 용례를 단어 결합자 (U+2060)로 대체하는 것을 권장하며, 이로 인해 U+FEFF는 BOM의 용도로만 사용할 수 있게 되었다. BOM의 UTF-8 표현은 (16진) 바이트열인 0xEF,0xBB,0xBF이다. 유니코드 표준은 UTF-8에 BOM을 허용하지만, 이는 필수가 아니며 권장 사항도 아니다. UTF-8에서 바이트 순서는 어떤 의미도 없으므로, UTF-8 내에서는 문서의 가장 앞에서 문서가 UTF-8로 인코딩되었거나, BOM이 있는 문서가 UTF-8로 변환된 것을 표시하는 이외의 용도는 없다. 또한 표준에서는 BOM이 존재하는 경우 다른 인코딩으로 변환했다가 되돌릴 때 정보가 손실되지 않고, 이에 의존하는 코드가 계속 작동하도록 제거하지 않는 것을 권장한다. IETF는 프로토콜이 (a) 항상 UTF-8을 사용하거나, (b) 인코딩 방식을 다른 방법으로 나타낼 수 있는 경우, "U+FEFF를 시그니처로 사용하는 것을 금지해야(SHOULD forbid) 한다"고 명시한다. BOM을 사용하지 않는 텍스트는 유니코드를 인식하지 못하는 일부 소프트웨어와 하위 호환된다. 이러한 예로는 문자열 리터럴에 ASCII가 아닌 바이트를 허용하지만 파일의 가장 앞에서는 금지하는 프로그래밍 언어가 있다. UTF-8은 올바른 UTF-8 문자열을 이루지 않는 바이트 조합이 모든 조합 중 큰 비율을 차지한다는 점에서 "성긴" 인코딩이라고 할 수 있다. 이진 데이터와 다른 인코딩으로 작성된 텍스트는 UTF-8로 올바르지 않은 바이트열을 포함할 가능성이 크며, 이에 대한 현실적인 예외는 텍스트가 완전히 ASCII 범위의 바이트로만 작성되었을 때뿐이다. 최근의 모든 인코딩은 ASCII 범위의 바이트로 ASCII 문자를 표현하므로, ASCII만 포함하는 텍스트는 이를 작성한 시스템에서 무슨 인코딩을 사용했는지와 무관하게 UTF-8로 해석해도 문제가 없다. 이러한 사항으로 인해 휴리스틱 접근을 이용해 BOM 없이도 UTF-8을 사용하고 있는지 높은 신뢰도로 판정할 수 있다. 마이크로소프트의 컴파일러와 인터프리터나 메모장 등 마이크로소프트 윈도우의 여러 소프트웨어는 휴리스틱을 이용하는 대신 BOM을 필수적인 매직 넘버로 취급한다. 이러한 프로그램은 UTF-8로 텍스트를 저장할 때 BOM을 추가하며, BOM이 있거나 파일에 ASCII만 포함되어 있는 경우가 아니라면 UTF-8을 해석하지 못한다. 버전 5.1까지의 파워셸은 UTF-8 XML 문서를 저장할 때 BOM을 추가했지만, PowerShell Core 6에서는 일부 명령에 -Encoding 스위치로 utf8NoBOM을 추가해 문서를 BOM 없이 저장할 수 있도록 하였다. 구글 독스 역시 문서를 다운로드 가능한 플레인 텍스트로 변환할 때 BOM을 추가한다. UTF-16에서, BOM(U+FEFF)은 파일의 첫 번째 문자로 배치되어 그 파일의 모든 16비트 코드 단위의 엔디언(바이트 순서)을 나타낼 수 있다. 이 스트림을 잘못된 엔디언으로 읽으려고 하면 바이트가 뒤집혀 문자 U+FFFE를 읽을 수 있으며, 이는 유니코드에서 텍스트에 등장해서는 안 되는 "비문자"(non-character)로 정의되어 있다. 문서가 빅 엔디언으로 작성되어 있을 경우, BOM 문자는 바이트열에서 0xFE 0xFF로 기록된다. 문서가 리틀 엔디언으로 작성되어 있을 경우, BOM 문자는 바이트열에서 0xFF 0xFE로 기록된다. 이들은 모두 올바른 UTF-8이 아니므로, 이러한 파일은 UTF-8로 인코딩되지 않았음을 알 수 있다. IANA에 등록된 문자 집합인 UTF-16BE와 UTF-16LE의 경우, 이 문자 집합의 이름으로 이미 바이트 순서가 결정되기 때문에 바이트 순서 표식을 사용해서는 안 된다. 이런 문서 내의 어떤 위치에든 BOM이 있을 경우 "폭과 줄 바꿈 없는 공백"으로 해석한다. BOM이 없더라도 텍스트가 UTF-16인지 및 어떤 엔디언을 사용했는지를 ASCII 문자를 이용해(즉, 0x20에서 0x7E 범위 혹은 0x0A(LF)와 0x0D(CR) 바이트에 인접한 0 바이트) 추측할 수 있다. 이러한 문자가 많이(즉, 무작위로 등장하는 경우보다 훨씬 자주) 등장할 경우 문서가 높은 확률로 UTF-16임을, 0이 짝수 번째로 등장하는지 홀수 번째로 등장하는지를 확인해 이 문서의 엔디언을 추론할 수 있다. 그러나 이 방법은 오진의 가능성이 있다. 유니코드 표준의 '적합성' (3.10장) 중 D98항에서는 "UTF-16 인코딩 스킴은 BOM으로 시작하거나 시작하지 않을 수 있다. 그러나, BOM이 없고 고수준의 프로토콜이 존재하지 않을 경우 UTF-16 인코딩 스킴의 바이트 순서는 빅 엔디언이다."라고 명시하고 있다. 고수준의 프로토콜이 언제 적용되는지는 해석의 여지가 있다. 예를 들어, 리틀 엔디언을 사용하는 컴퓨터에 저장된 파일은 암시적으로 UTF-16LE로 인코딩되었다고 할 수 있다. 이런 이유로 빅 엔디언 추정 조항은 무시되는 경우가 많다. HTML5에 사용된 W3C/WHATWG 인코딩 표준에서는 "utf-16"이나 "utf-16le"로 표시된 콘텐츠를 리틀 엔디언으로 해석하는 것으로 명시하지만, 바이트 순서 표식이 있을 경우 이 BOM을 다른 모든 사항보다 우선한다. UTF-16을 바이트 기반 인코딩으로 해석하는 프로그램은 무의미한 문자열을 표시하지만, UTF-16 표현의 하위 바이트가 ASCII 코드와 같으므로 ASCII 문자는 알아볼 수 있다. 상위 바이트 0은 공백이나 점 등 일정한 문자로 표시되거나 아예 표시되지 않을 수도 있다. UTF-32에도 BOM을 사용할 수는 있지만, 이 인코딩은 전송에 거의 사용되지 않는다. 이 이외에는 UTF-16과 동일한 규칙이 적용된다. 리틀 엔디언 UTF-32에서의 BOM 패턴은 리틀 엔디언 UTF-16에서 BOM 다음에 널 문자가 오는 것과 같으며, 이와 같이 서로 다른 인코딩에서 BOM 패턴이 같은 경우는 드물다. BOM을 이용해 인코딩을 추론하는 경우 문서가 UTF-32인지 널 문자로 시작하는지를 결정해야 한다. 아래 표는 BOM 문자가 다양한 인코딩에서 바이트열로 어떻게 표현되는지와 이를 구식 인코딩(CP1252, C0 제어 문자의 경우 캐럿 표기)에서 어떻게 출력되는지를 정리한 것이다. 이 인코딩은 코드의 단위가 1바이트로, 바이트를 "잘못된" 순서로 읽을 수 없기 때문에 엄밀히 말해 "바이트 순서" 표식의 기능을 하지는 않는다. 그러나 BOM을 이용함으로써 그 다음에 오는 텍스트의 인코딩을 표시할 수는 있다. 다음에 오는 문자에 따라 형태가 달라진다. SCSU는 U+FEFF 문자의 다른 인코딩을 허용하며, 이 형태는 UTR #6에서 권장하는 시그니처이다. “FAQ - UTF-8, UTF-16, UTF-32 & BOM”. 《Unicode.org》. 2017년 1월 28일에 확인함.  “The Unicode® Standard Version 9.0” (PDF). 《The Unicode Consortium》.  “The Unicode Standard 5.0, Chapter 2:General Structure” (PDF). 36쪽. 2009년 3월 29일에 확인함. Table 2-4. The Seven Unicode Encoding Schemes  “The Unicode Standard 5.0, Chapter 2:General Structure” (PDF). 36쪽. 2008년 11월 30일에 확인함. Use of a BOM is neither required nor recommended for UTF-8, but may be encountered in contexts where UTF-8 data is converted from other encoding forms that use a BOM or where the BOM is used as a UTF-8 signature  “FAQ - UTF-8, UTF-16, UTF-32 & BOM: Can a UTF-8 data stream contain the BOM character (in UTF-8 form)? If yes, then can I still assume the remaining UTF-8 bytes are in big-endian order?”. 《Unicode.org》. 2009년 1월 4일에 확인함.  “Re: pre-HTML5 and the BOM from Asmus Freytag on 2012-07-13 (Unicode Mail List Archive)”. 《Unicode.org》. 2012년 7월 14일에 확인함.  “Bug ID: JDK-6378911 UTF-8 decoder handling of byte-order mark has changed”. 《Bugs.sun.com》. 2017년 1월 28일에 확인함.  Yergeau, Francois (November 2003). UTF-8, a transformation format of ISO 10646. IETF. RFC 3629. https://tools.ietf.org/html/rfc3629. Retrieved May 15, 2014.  Alf P. Steinbach (2011). “Unicode part 1: Windows console i/o approaches”. 2012년 3월 24일에 확인함. However, since the C++ source code was encoded as UTF-8 without BOM (as is usual in Linux), the Visual C++ compiler erroneously assumed that the source code was encoded as Windows ANSI.  “UTF-16LE”. 《Encoding Standard》. WHATWG.  “Decode”. 《Encoding Standard》. WHATWG.  “RFC 3629 - UTF-8, a transformation format of ISO 10646”. 《Tools.ietf.org》. 2003년 11월 8일. 2017년 1월 28일에 확인함.  https://unicode.org/L2/L2021/21038-bom-guidance.pdf https://docs.sdl.com/791187/581899/sdl-contenta-5-7/representations-of-boms-by-encoding Markus Scherer. “UTS #6: Compression Scheme for Unicode”. 《Unicode.org》. 2017년 1월 28일에 확인함.