fix(detect): treat C0 control characters as valid UTF-8 - #64
Merged
polygonplanet merged 1 commit intoAug 25, 2026
Merged
Conversation
`isUTF8()` only accepted TAB, LF, CR and printable ASCII, so a UTF-8
string containing any other C0 control character was not detected as
UTF-8.
This is inconsistent with `isASCII()`, which accepts every byte in the
ASCII range except ESC (0x1B). The same byte was therefore reported as
ASCII but not as UTF-8, even though every ASCII byte is valid UTF-8.
const utf8 = Buffer.from('UTF8の文字列です', 'utf8');
Encoding.detect(Buffer.from([0x08])); // 'ASCII'
Encoding.detect(utf8); // 'UTF8'
Encoding.detect(Buffer.concat([utf8, bs])); // 'UNICODE' <- expected 'UTF8'
Accept the whole ASCII range except ESC, which is left out to match
`isASCII()` and to keep ISO-2022-JP out of `isUTF8()`.
This does not widen the result of `detect()`, because `isBINARY`
(0x00-0x07, 0xFF) and `isJIS` are both tried before UTF8 in
`Encoding.orders`. Only the previously misdetected inputs change:
+BS (0x08) UNICODE -> UTF8
+VT (0x0B) UNICODE -> UTF8
+FF (0x0C) UNICODE -> UTF8
+DEL (0x7F) UNICODE -> UTF8
+NUL (0x00) BINARY -> BINARY (unchanged)
ISO-2022-JP JIS -> JIS (unchanged)
Fixes polygonplanet#49
Owner
|
@hiros0921 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #49.
Problem
isUTF8()accepts only TAB, LF, CR and printable ASCII, so a UTF-8 string that contains any other C0 control character is not detected as UTF-8.This is inconsistent with
isASCII(), which accepts every byte in the ASCII range except ESC (0x1B). The same byte is reported as ASCII but not as UTF-8, even though every ASCII byte is valid UTF-8 by definition.Measured on 2.2.0, appending one control character to the same UTF-8 string:
detect()UNICODEUNICODEUNICODEUNICODEUNICODEUTF8BINARYChange
Accept the whole ASCII range except ESC:
ESC is left out to match
isASCII(), so that ISO-2022-JP data is not reported as UTF-8 by a directisUTF8()call. Please let me know if you would rather have ESC accepted as well —detect()is unaffected either way, sinceisJISruns before UTF8.Why
detect()does not get looserEncoding.ordersisUTF32 → UTF16 → BINARY → ASCII → JIS → UTF8 → EUCJP → SJIS → UNICODE.isBINARY(0x00-0x07, 0xFF) andisJISare both tried before UTF8, so the inputs they already claim are unchanged. Only the previously misdetected inputs change:UNICODEUTF8BINARYBINARY(unchanged)Tests
Added
detect > UTF-8 with C0 control characters. The existing suite still passes (178 → 179).I checked that the new test actually fails without the change:
The test also pins the two behaviours that should not change:
0x00still yieldsBINARY, and ISO-2022-JP data still yieldsJISwhiledetect(jis, 'UTF8')staysfalse.Notes
I did not commit
encoding.js/encoding.min.js, since #62 and #63 only touchedsrc/andtests/. Happy to rebuild them if you prefer them in the PR.