Switch stage-3 triage from NUL sniff to UTF-8 validity
The NUL-byte heuristic misfiled any non-ASCII UTF-8 text (accents, CJK, emoji) as binary and let non-NUL control bytes through as text. is_binary now calls a file text when its 8000-byte sniff window is valid UTF-8 with no control bytes outside the text-safe set (tab/newline/CR/ESC/etc). - trim_truncated_utf8 drops a multi-byte char split by the window edge so it isn't mistaken for malformed bytes. - NUL still classifies as binary (valid UTF-8 scalar, non-text control). - Expanded tests: Unicode, ANSI logs, stray control byte, malformed UTF-8, boundary-split char; updated README stage-3 description.
This commit is contained in:
17
README.md
17
README.md
@@ -125,12 +125,17 @@ them into two coarse buckets so downstream tooling can treat them differently:
|
||||
- **`data/binary/`** — the file looks like binary data.
|
||||
- **`data/text/`** — the file looks like text.
|
||||
|
||||
The test is the classic **NUL-byte sniff** (the same heuristic `git` and
|
||||
`file(1)` use): read the first 8000 bytes and, if any is NUL, call it binary,
|
||||
else text. It's cheap (no full read) and reliable in practice — text encodings
|
||||
don't embed NUL bytes, while binary formats almost always do near the start. An
|
||||
empty file has no NUL, so it's treated as text. This is deliberately simple for
|
||||
now; richer handling can hang off either bucket later (`src/content.jl`).
|
||||
The test is a **UTF-8 sniff**: read the first 8000 bytes and call the file text
|
||||
when that window is valid UTF-8 and holds no control bytes outside the text-safe
|
||||
set (tab, newline, CR, and friends, plus ESC for ANSI-colored logs); otherwise
|
||||
binary. It's cheap (no full read) and Unicode-aware — unlike the older NUL-byte
|
||||
or printable-ASCII heuristics, it keeps non-ASCII text (accents, CJK, emoji) in
|
||||
`text/` instead of misfiling it, while binary formats — which rarely form valid
|
||||
UTF-8 near their start — still land in `binary/`. A NUL byte is valid UTF-8 but
|
||||
not a text control byte, so it still reads as binary. A multi-byte character
|
||||
split by the 8000-byte boundary is trimmed before the check so it isn't mistaken
|
||||
for malformed bytes. An empty file is treated as text. Richer handling can hang
|
||||
off either bucket later (`src/content.jl`).
|
||||
|
||||
## The queue seam (→ RabbitMQ later)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user