Detect¶
Detect the character encoding of bytes without parsing them, a successor to chardet.detect, cchardet.detect, and
charset_normalizer.from_bytes. The pipeline is the one turbohtml.parse() runs for bytes input – the
WHATWG sniff (byte-order mark, then a <meta> prescan), a content detector that scores byte-pair frequencies against
per-encoding character-class models, then the spec’s windows-1252 fallback – so a standalone detection and
parse(data, detect_encoding=True) agree, except that a byte-order mark reports its own label here (how it
decides). Decode with EncodingMatch.codec, not
EncodingMatch.encoding: a WHATWG name and the CPython codec answering to it
name different encodings.
- turbohtml.detect.detect(data, options=None, /)[source]¶
Detect the character encoding of a byte string, the
chardet.detect/cchardet.detectsuccessor.- Parameters:
- Return type:
- Returns:
the best match; its
encodingisNonewhen the input is empty or every candidate was ruled out. A leading byte-order mark reports its own label (UTF-8-SIG,UTF-16LE/BE,UTF-32LE/BE) withbomset, so a caller can strip it.- Raises:
TypeError – when
datais not a bytes-like object.
- turbohtml.detect.detect_all(data, options=None, /)[source]¶
Detect the character encoding and rank every plausible candidate, the
chardet.detect_allsuccessor.- Parameters:
- Return type:
- Returns:
the matches best first,
detect()’s result leading;[EncodingMatch(None, 0.0, None)]when the input is empty or every candidate was ruled out. A leading byte-order mark collapses the ranking to one match carrying its own label andbom.- Raises:
TypeError – when
datais not a bytes-like object.
- class turbohtml.detect.EncodingMatch(encoding, confidence, language, bom=False, codec=None)[source]¶
One detection result:
chardet.detect’s{"encoding", "confidence", "language"}dict as a typed record.encodingis the WHATWG canonical name (the same stringturbohtml.Document.encodingreports), orNonewhen the input is empty or every candidate was ruled out. A leading byte-order mark reports the mark’s own label instead:"UTF-8-SIG"for a UTF-8 mark (so a caller can decode with theutf-8-sigcodec to strip it), and"UTF-16LE"/"UTF-16BE"/"UTF-32LE"/"UTF-32BE"for the UTF-16 and UTF-32 marks, which a mark identifies unambiguously with no heuristic.codecis the name to handbytes.decode();encodingis not. A WHATWG name and the CPython codec that answers to it are different encodings:bytes.decode("big5")reaches a strict subset of the spec’s Big5,koi8-ureaches KOI8-U where the spec means KOI8-RU, andx-mac-cyrillicreaches no codec at all. Socodecnames awhatwg-*codec this module registers, whose decoder is the oneturbohtml.parse()uses, anddata.decode(match.codec)reproduces the parser’s text. It isNonewith aNoneencoding. Those codecs decode only: encoding to a legacy charset is a separate spec algorithm turbohtml omits.confidenceis 1.0 for a certain result (a byte-order mark, a<meta>declaration, structurally valid UTF-8, escape-driven ISO-2022-JP, or pure ASCII), the candidate’s share of the positive frequency scores for a content-scored result, and 0.0 for the windows-1252 fallback chosen with no positive evidence.languagenames the language the winning frequency model targets ("Russian"for windows-1251,"Japanese"for Shift_JIS, …); it isNonefor UTF-8 and the Latin encodings whose model spans several languages.bomis true only when a byte-order mark decided the result, telling a caller the decoded text still carries the mark unless the codec strips it.
- class turbohtml.detect.Detection(threshold=0.0, language=None, allowed=None, excluded=frozenset({}))[source]¶
Options for
detect(),detect_all(), andEncodingDetector.- Parameters:
threshold (
float) – the confidence floor; a candidate below it is dropped, and when every candidate falls below it the result’sencodingisNone. The default 0.0 always answers, likechardet.detect.language (
str|None) – prefer this language when the evidence is ambiguous: candidates whose frequency model targets it (the valueEncodingMatchreports as its language) rank ahead of the rest, provided they scored positively.allowed (
frozenset[str] |None) – when set, only these encodings (WHATWG names, any case) may be returned.excluded (
frozenset[str]) – these encodings are never returned; mutually exclusive withallowed.
- class turbohtml.detect.EncodingDetector(options=None, /)[source]¶
Incremental detection over a byte stream, mirroring chardet’s
UniversalDetector.Call
feed()with each chunk,close()for the result, andreset()to reuse the instance on another stream.doneturns true as soon as the result cannot change (a leading byte-order mark, orclose()), so a reader loop can stop early. Feeding buffers the chunks andclose()detects once over the whole stream, so the result always equalsdetect()of the concatenated bytes. An instance is not thread-safe; use one per stream.- Parameters:
options (
Detection|None) – the detection options; defaults toDetection(always answer, no constraints).
- done: bool¶
Whether the result can no longer change: a leading byte-order mark was seen, or
close()ran.
- property result: EncodingMatch | None¶
The match
close()computed, orNonewhile the stream is still open.
Detect the natural language of text, a successor to whatlang, resiliparse.parse.lang, and trafilatura’s language
filter. detect_language() finds the dominant Unicode script and ranks the languages sharing it by a
character-trigram model, reading the visible text rather than an <html lang> attribute.
- turbohtml.detect.detect_language(text, options=None, /)[source]¶
Detect the natural language a string is written in, the
whatlang/resiliparsecontent-language successor.The detector finds the dominant Unicode script, then ranks the languages that share it by the similarity between the text’s most frequent character trigrams and each language’s embedded profile. It reads the visible text only; it does not consult an
<html lang>attribute.- Parameters:
text (
str) – the text to classify; extract it from a document first (e.g.node.text).options (
LanguageDetection|None) – the detection options; defaults toLanguageDetection(always answer, no constraints).
- Return type:
- Returns:
the best match; its
languageisNonewhen the text has no modeled script, every candidate was ruled out, or the confidence fell belowthreshold.- Raises:
TypeError – when
textis not astr.
- class turbohtml.detect.LanguageMatch(language, confidence, script, name=None)[source]¶
One language-detection result: the ISO 639-3 code, a confidence, the Unicode script, and an English name.
languageis the ISO 639-3 code the text was written in ("eng","deu","cmn", …), orNonewhen the text carries no script the detector models (it is empty, or all punctuation, digits, emoji, or symbols) or every candidate for its script was ruled out byLanguageDetection.confidenceruns 0.0 to 1.0: it is 1.0 for a script only one modeled language uses (Greek, Georgian, Korean, …) and for a clear trigram winner, and drops toward 0.0 as the top two candidates for a shared script (Latin, Cyrillic, Arabic, Devanagari, Hebrew) converge – the usual signal that the text is too short to separate them.scriptis the Unicode script name the text is written in ("Latin","Cyrillic","Han"reported as"Mandarin", …), orNonewith aNonelanguage.nameis the English name of the language ("English","German","Mandarin", …), orNonewith aNonelanguage.
- class turbohtml.detect.LanguageDetection(threshold=0.0, allowed=None, excluded=frozenset({}))[source]¶
Options for
detect_language().- Parameters:
threshold (
float) – the confidence floor; a result below it is reported asLanguageMatch(None, 0.0, None)so a short or ambiguous input does not masquerade as a confident answer. The default 0.0 always answers.allowed (
frozenset[str] |None) – when set, only these languages (ISO 639-3 codes) may be returned; a text whose script has no allowed language yields no match. Constrains every script, including the single-language ones.excluded (
frozenset[str]) – these languages are never returned; mutually exclusive withallowed.
Normalize text to a Unicode normalization form (UAX #15), a C successor to unicodedata.normalize() and
unicodedata.is_normalized(). normalize() runs all four forms – NFC, NFD, NFKC, NFKD – over the pinned
tables generated from the interpreter’s own unicodedata, so the two agree exactly; a quick check returns
already-normalized text untouched.
- turbohtml.detect.normalize(form, text, /)[source]¶
Return text in a Unicode normalization form (UAX #15), the C successor to
unicodedata.normalize().The four forms pair a decomposition depth with whether the result is recomposed:
NFDfully decomposes and canonically orders combining marks,NFCdecomposes then recomposes, and theNFK*forms decompose compatibility equivalents too (folding ligatures, superscripts, and width variants onto their plain characters).NFCis what you want to compare or store user text so"é"written as a base plus a combining accent equals"é"written as one code point;NFKCadditionally flattens presentation variants. A quick check returns already-normalized text (the common case) without allocating.- Parameters:
- Return type:
- Returns:
the normalized string, the same object when it was already normalized.
- Raises:
ValueError – when form is not one of the four names.
TypeError – when text is not a
str.
- turbohtml.detect.is_normalized(form, text, /)[source]¶
Return whether text is already in a Unicode normalization form, the
unicodedata.is_normalized()peer.This decides the same question as
normalize(form, text) == textbut the quick check settles almost every string in a single scan, without building the normalized copy.- Parameters:
- Return type:
- Returns:
Truewhen text is unchanged bynormalize()for form.- Raises:
ValueError – when form is not one of the four names.
TypeError – when text is not a
str.