Tabulate n-gram matches.
A fast command-line tool for checking occurrence frequency of patterns across a collection of files — paths, names, or any line-based dataset. Give it a list of file paths and it tells you which multi-word patterns appear most often, so you can spot recurring themes, near-duplicates, and naming conventions across tens or hundreds of thousands of files.
Built for the question "I have 100,000 paths — what phrases keep repeating?" — common in file library analysis, course-archive deduplication, content classification, and naming-convention audits.
Written in Go, statically linked, single binary. Small dependency set
(golang.org/x/text for Unicode normalization; charmbracelet
bubbletea/bubbles for the optional interactive -tui mode). Runs
anywhere.
# Build for current host
make build
# Find the most common patterns in a list of paths
find /library -type f | ./tabgram
# Restrict to specific file types
find /library -type f | ./tabgram -type ebook,document
# Show longer patterns (4, 5, 6-grams)
./tabgram -n 4,5,6 <your-corpus>.txt
# Browse interactively, drill into which paths contain a pattern
./tabgram -tui <your-corpus>.txtDetailed docs are split by topic:
- Build & install — cross-compile matrix, static linking guarantees, versioned releases.
- Usage & flags — every flag with examples,
input modes (stdin/file/
-input), output format. - Examples — recipes for books, movies, courses, naming audits, dedup prep.
- Performance — numbers, memory profile, tuning tips.
- Checking occurrence frequency of name patterns in a file collection — "which course titles repeat?", "which release groups dominate this archive?", "which authors show up most?", "which codec/source tags appear together?"
- Naming-convention audits across a file library — find that 80% of paths use a particular date format, that release tags are inconsistent, or that a single course name appears under multiple variant spellings.
- Deduplication prep — spot near-duplicates that differ only by
separator (
foo-barvsfoo.barvsfoo_barare merged automatically). - Content classification of a mixed corpus — once you know which
patterns appear most in each
findoutput, you can tag and route.
- TB-scale file collections where the working set doesn't fit in RAM — use Count-Min Sketch or Misra-Gries summaries instead.
- Noisy OCR text with thousands of unique character-level patterns — add language-specific tokenization first.
- Need exact phrase boundaries — tabgram collapses variant separators,
so
"the quick brown fox"and"the.quick.brown.fox"collapse to one pattern by design. - Binary file contents — tabgram reads paths/filenames, not file bytes.
.
├── README.md ← this file
├── main.go ← CLI entry point
├── stoplist.txt ← default stoplist (override with -stoplist)
├── Makefile ← build, test, cross-compile matrix
├── go.mod / go.sum
├── docs/ ← detailed documentation
│ ├── build.md
│ ├── usage.md
│ ├── examples.md
│ └── performance.md
├── detector/
│ ├── normalize.go ← tokenization pipeline
│ ├── stoplist.go ← stoplist loader
│ ├── detector.go ← CountMap, n-gram extractors, PMI filter
│ ├── types.go ← file-type registry
│ └── *_test.go ← unit tests
└── testdata/
├── README.md
├── seed.txt ← 61 hand-crafted paths (correctness)
├── big.txt ← 100k synthetic (gitignored)
├── gen/gen.go ← deterministic generator
└── private/ ← gitignored — drop your own real data here
MIT.