Settings

Theme

Fixing a bug with byte order marks

alexwlchan.net

6 points by surprisetalk 7 days ago · 10 comments

Reader

flohofwoe a day ago

Ugh, why are BOMs even still a thing in the 21st century? E.g. when will Windows finally arrive in the late 1990s and switch to UTF-8 for everything?

The UTF-8 BOM is especially bizarre because UTF-8 is completely endian-agnostic (so this "UTF-8 Byte Order Mark" is at most an indicator that this file is UTF-8 encoded, but guess what? Outside the Windows bubble, all text files are UTF-8 anyway).

  • gdwatson a day ago

    Windows bought into Unicode hard before Unicode expanded beyond 16 bits. The consequence is that its native strings are theoretically UTF-16, but often behave like UCS-2, allowing random halves of surrogate pairs. Windows APIs reflect that, Windows filenames reflect that, and translation into UTF-8 has to reflect that -- somehow. It's not great.

    Personally I'd like a world where Unicode gave up all the compromises that come with supporting UTF-16. But presumably burning all your early adopters is not a winning strategy.

    • flohofwoe a day ago

      > But presumably burning all your early adopters is not a winning strategy.

      This topic is so old that most early adaptors probably have retired by now ;)

      • gdwatson 18 hours ago

        Fair. If only they'd retired those APIs, too.

        I remember when Windows gained experimental support for a UTF-8 locale usable with its 8-bit APIs. I used to run it at work; it had some issues at first, but most got shaken out pretty quickly. I don't know its current state, but that's probably the best route to UTF-8 on Windows if MS would lean into it.

orangepanda a day ago

> A byte order mark is a special use of the zero width no-break space character U+FEFF at the beginning of a text file

Isnt BOM allowed to appear anywhere in the file, because of file concatenation?

  • brewmarche a day ago

    No, a ZWNBSP that’s not at the start is just a regular ZWNBSP. Can be used to break up ligatures for example

    • brewmarche 12 hours ago

      PS: Did some research and while it is true that a ZWNBSP will break up ligatures in many systems, that’s not its intended use. It’s there to prevent line breaks (up to Unicode 3.2), nowadays only kept for compatibility outside of BOM. Modern Unicode uses U+2060 WORD JOINER to express the same intention.

      The old Unicode rules for ZWNBSP are also quite tricky: you are not supposed to ignore the first ZWNBSP if you already know the encoding. Which means to express an initial actual ZWNBSP you need to write two of them if the encoding is unknown to the receiver and only one of them if known.

      > Where the character set information is explicitly marked, such as in UTF-16BE or UTF-16LE, then all U+FEFF characters, even at the very beginning of the text, are to be interpreted as zero width no-break spaces. Similarly, where Unicode text has known byte order, initial U+FEFF characters are also not required and are to be interpreted as zero width no-break spaces. For example, for strings in an API, the memory architecture of the processor provides the explicit byte order. For databases and similar structures, it is much more efficient and robust to use a uniform byte order for the same field (if not the entire database), thereby avoiding use of the byte order mark. Systems that use the byte order mark must recognize that an initial U+FEFF signals the byte order; it is not part of the textual content. It should be removed before processing, because otherwise it may be mistaken for a legitimate zero width no-break space. To represent an initial U+FEFF ZERO WIDTH NO-BREAK SPACE in a UTF-16 file, use U+FEFF twice in a row. The first one is a byte order mark; the second one is the initial zero width no-break space.

      — Unicode 3.0 Standard, p. 325 <https://www.unicode.org/versions/Unicode3.0.0/ch13.pdf>

      (With modern Unicode you can write WJ or ZWNBSP,WJ and there is no problem)

  • nvme0n1p1 a day ago

    No, it's only allowed at the start. How would that even work? If an app sees a UTF-32 BOM halfway through a file should it interpret the rest of the file as UTF-32? Are there any apps that handle text files like this?

mr_mitm a day ago

I hate the BOM so much. It causes so many subtle issues and I don't even understand why it's needed.

remnavi a day ago

The csv.DictReader version of this bug is the one that got me. Open a UTF-8-with-BOM CSV as plain utf-8 and your first column name comes back with an invisible U+FEFF glued to the front of it, so every lookup on that one field fails while the other columns behave perfectly. You end up suspecting the source data, the header row, anything except the encoding.

json.loads has a similar tell: a leading BOM gives you "Expecting value: line 1 column 1 (char 0)", which reads like malformed JSON when the JSON is fine.

Same fix, utf-8-sig at the open, and I think the lesson generalises past subtitles: deal with encoding once at the I/O boundary so nothing downstream ever needs to know a BOM existed. Mid-file BOMs like yours are what it looks like when that leaks.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection