Choosing strategies
Start with EnsembleDetector() for English screening. It combines three English
language heuristics with mojibake, keyboard adjacency, and control-character
checks. Meaningful Hindi may be flagged; this is expected behavior.
The english_extended profile adds localized anomalies, repetition, and pattern
matching. Measure its false positives before using it for automatic rejection.
Use corruption for encoding/control artifacts without English plausibility
scoring. spoofing is a Unicode script/confusable heuristic, not a full phishing
or Unicode security implementation. Profile membership is listed in Detection Strategies.
Control characters: new in 0.9.0
Strategy.CONTROL_CHARACTERS examines raw Unicode characters before English
normalization. It detects unexpected control characters, U+FFFD replacement
characters, lone surrogates, and combining-mark runs exceeding a configurable
limit. Ordinary tabs, line breaks, accents, and emoji joiners are not themselves
flagged. This strategy belongs to english, english_extended, and
corruption.
from pygarble import GarbleDetector, Strategy
detector = GarbleDetector(
Strategy.CONTROL_CHARACTERS,
strategy_kwargs={"max_combining_run": 8},
)
assert detector.predict("hello\x00world") is True
assert detector.predict("hello\nworld") is False
assert detector.predict("hello\ufffdworld") is True
max_combining_run defaults to 8 and must be a positive integer. A detected
artifact scores 0.9; otherwise the score is 0.0. A detector threshold above 0.9
therefore suppresses these detections. These are fixed heuristic scores.
Localized anomalies: new in 0.9.0
Strategy.LOCAL_ANOMALY finds severe unfamiliar tokens or clusters of suspicious
tokens in otherwise readable English. It uses the bundled English dictionary,
shared bigram likelihood, and bounded token windows. It belongs to
english_extended and can also be selected independently.
from pygarble import GarbleDetector, Strategy
detector = GarbleDetector(
Strategy.LOCAL_ANOMALY,
strategy_kwargs={
"min_word_length": 8,
"word_log_prob_threshold": -5.5,
"window_words": 4,
},
)
text = "Please review qxzjkwpvm before delivery."
result = detector.analyze(text)
assert result.garbled is True
assert any(text[s.start:s.end] == "qxzjkwpvm" for s in result.spans)
The example shows the defaults. min_word_length is the minimum length for an
individual severe-token span; windows can use suspicious tokens of at least four
characters. word_log_prob_threshold must be finite and negative; a more
negative value requires a lower likelihood. window_words must be an integer
from 1 to 32. A window requires at least two suspicious tokens, so choosing 1
disables window detections while retaining individual-token checks.
Detected anomalies score 0.8. Dictionary words, allowlisted terms, and structured tokens excluded by shared preprocessing do not become suspicious candidates. This is not a grammaticality or semantic-coherence check, and rare English words can still produce false positives.
Keyboard paths and repetition
Keyboard adjacency supports QWERTY, AZERTY, and QWERTZ with digit-row neighbors. It checks straight rows and substantially covered adjacent-key paths. It does not detect every possible keyboard walk. Repetition detects character, word, and bounded phrase repetition; intentional repetition can also be flagged.
from pygarble import GarbleDetector, Strategy
keyboard = GarbleDetector(
Strategy.KEYBOARD_ADJACENCY, keyboard_layout="azerty"
)
assert keyboard.predict("azerty") is True
repetition = GarbleDetector(Strategy.REPETITION)
assert repetition.predict("hello " * 10) is True
Tune on your own data
All 28 strategies remain individually available. Check both valid English inputs and expected corruption, including domain terms, identifiers, and short strings. Scores are not calibrated probabilities, and no strategy guarantees zero false positives. See API Reference for voting and abstention, and Upgrading to 0.9.0 for changes from the previous default. A conditional-trigram experiment remains in repository evaluation tooling; no additional trigram model is shipped by 0.9.0.