ahocorasick_rs
A fast Aho-Corasick multi-pattern string and byte search library for Python, backed by Rust.
Repository Health
Technical Analysis
ahocorasick-rs is a Python binding for the Rust aho-corasick crate, giving Python code fast multi-pattern string and byte searching without hand-rolling a C extension. Given a list of patterns, it builds a single automaton once and then scans a haystack in one pass, returning each match’s pattern index and start/end offsets (as Unicode codepoints for str, or raw byte offsets for buffer-like bytes objects) instead of running one str.find() or regex alternation per pattern.
Because it wraps a mature, widely-used Rust implementation, users can choose between three match-kind semantics (standard, leftmost-first, leftmost-longest) and four underlying automaton types (heuristic default, noncontiguous NFA, contiguous NFA, or DFA) to trade construction time, memory, and search speed depending on pattern-set size. It is positioned explicitly as a faster, actively maintained alternative to pyahocorasick, claiming 1.5x-7x speedups in the project’s own benchmarks, and ships prebuilt wheels for CPython 3.10 through 3.14 (including free-threaded 3.14t) across Linux, macOS, and Windows.
What You Get
- AhoCorasick class for searching str patterns against a str haystack, returning matches as (pattern_index, start, end) tuples or as matched strings
- BytesAhoCorasick class supporting bytes, bytearray, memoryview, and other objects implementing the Python buffer protocol
- Three configurable match-kind strategies (Standard, LeftmostFirst, LeftmostLongest) plus optional overlapping-match retrieval
- Four automaton implementation choices (heuristic default, NoncontiguousNFA, ContiguousNFA, DFA) to tune construction time vs. memory vs. search speed
- Full type stubs (py.typed marker plus a .pyi file) for static type checking under mypy —strict
Common Use Cases
- Scanning log lines or documents for thousands of known keywords or indicators of compromise at once
- Content filtering, profanity detection, or PII redaction across many patterns without per-pattern regex overhead
- Tokenizing or annotating text against large dictionaries, such as named-entity gazetteers
- Searching binary payloads or network captures for multiple byte signatures
Under The Hood
Architecture
The project is a thin, single-module Rust wrapper (src/lib.rs) around the aho-corasick crate, exposing two PyO3 classes: PyAhoCorasick for str patterns and PyBytesAhoCorasick for buffer-protocol objects. There is no internal layering beyond this binding boundary — Python calls flow directly into AhoCorasickBuilder, and match iterators are converted back into Python tuples/lists, with a dedicated get_byte_to_code_point helper translating Rust’s UTF-8 byte offsets into the Unicode codepoint offsets Python users expect. Because the wrapper adds no abstraction of its own beyond type conversion and GIL management, most of its code would need to change if the underlying aho-corasick crate’s API changed, but the boundary is narrow and clean rather than tangled.
Tech Stack
Built with PyO3 0.28 and the maturin build backend (pyproject.toml declares maturin>=1.0,<2.0 as the build system), wrapping the aho-corasick crate (v1) with itertools 0.14 used to chunk large pattern iterators. The Python side has effectively no runtime dependencies beyond typing_extensions on Python <3.12. CI builds and publishes wheels via pyo3/maturin-action across Linux (manylinux), macOS (universal2), and Windows, for CPython 3.10 through 3.14 including the free-threaded 3.14t build, publishing to PyPI on tagged releases via trusted publishing.
Code Quality
Tests (tests/test_ac.py, tests/test_ac_bytes.py) use pytest together with Hypothesis for property-based testing, parametrized across every combination of store_patterns, implementation, and match kind. Type safety is enforced with a py.typed marker, a full .pyi stub file, and mypy --strict in CI; style is enforced with flake8 and black --check. The Rust side pins its toolchain (rust-toolchain.toml) and runs clippy and rustfmt in CI, and the extension module code includes detailed safety-rationale comments around an unsafe buffer transmute used to support free-threaded Python. The CI matrix spans four operating systems (including ARM) and six Python configurations.
API Design
The public surface is small and idiomatic: construct AhoCorasick(patterns) or BytesAhoCorasick(patterns) once, then call find_matches_as_indexes() or find_matches_as_strings() with sensible defaults (matchkind=Standard, overlapping=False). Naming mirrors Python’s own str/bytes duality, and the README documents every configuration knob (match kind, store_patterns heuristic, implementation choice) with runnable REPL examples, so getting started requires only a couple of lines of code.