textnorm

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package textnorm cleans recovered text once, at the graph boundary.

Doing it here rather than per format is the same reasoning that makes every output render from a single graph: a rule applied in the Markdown writer and forgotten in the JSON writer is not a rule, it is a coincidence. Every emitted format inherits whatever happens in this package, and nothing downstream is permitted to re-clean text.

What this defends against

Text extracted from a third-party page goes straight into a model's context. Unicode offers several ways to make a string read one way to a human and another way to a machine, and none of them are visible in a diff:

  • Bidirectional overrides can reverse the displayed order of a run, so that text reading "delete nothing" on screen is "gnihton eteled" in the buffer -- or the reverse, which is the direction that matters here.
  • Zero-width characters split a word so it survives a human read and a substring search but reaches the model as separate tokens, which is how a filtered phrase gets past a filter.
  • Tag characters (U+E0000 block) are invisible everywhere and were used for exactly this in the wild.

None of these appear in legitimate rendered prose in a way that survives removal, so removal is safe and the absence of them is worth guaranteeing.

Why the version number exists

Changing what this package does changes every artifact's content hash, which invalidates every cache everywhere. That has to be a decision, not an accident, so the version is part of the hash input: a consumer can see that the normalizer changed rather than inferring it from a hash that moved for no visible reason.

Index

Constants

View Source
const Version = 1

Version identifies the normalization rules. It is an input to every content hash, so bumping it deliberately invalidates caches.

Variables

This section is empty.

Functions

func CleanString

func CleanString(s string) string

CleanString is the convenience form for callers that do not need the report.

func Truncate

func Truncate(s string, n int) (string, bool)

Truncate cuts a string to n runes without splitting one, appending an ellipsis when it cut. Metadata channels are capped rather than trusted, and a cap that splits a rune produces mojibake in every consumer.

Types

type Result

type Result struct {
	Text string
	// Removed counts control characters stripped.
	Removed int
	// HadBidi is true when directional override characters were present. This
	// is worth surfacing: unlike a stray zero-width space, a bidi override in
	// body copy is almost never accidental.
	HadBidi bool
	// HadInvisible is true when zero-width or tag characters were present.
	HadInvisible bool
}

Result reports what normalization had to remove. A caller that wants to know whether a page was playing games can look at this rather than diffing.

func Clean

func Clean(s string) Result

Clean normalizes a run of text.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL