|
Download README.md from Snapkitty/snapkitty-regex: direct link, hf CLI and curl.
- Browser
- Download file 4.31 kB
-
https://huggingface.co/Snapkitty/snapkitty-regex/resolve/main/README.md
- Command line
-
hf download hf://Snapkitty/snapkitty-regex/README.md
-
curl -L -o README.md https://huggingface.co/Snapkitty/snapkitty-regex/resolve/main/README.md
4.31 kB
| license: agpl-3.0 | |
| tags: | |
| - snapkitty | |
| - october-2026-drop | |
| - c | |
| - python | |
| - regex | |
| - thompson-nfa | |
| - zero-dependency | |
| - developer-tools | |
| > Mirrored from [https://github.com/SNAPKITTYWEST/snapkitty-regex](https://github.com/SNAPKITTYWEST/snapkitty-regex) at commit `b14a2eb`. Part of the **SnapKitty October 2026 main drop**. | |
| # snapkitty-regex | |
| A Thompson NFA regular expression engine in C — under 700 lines, zero | |
| dependencies, no exponential backtracking, ever. | |
| Built as an exercise from the guides in | |
| [AHMADALIPARR/build-your-own-x](https://github.com/AHMADALIPARR/build-your-own-x) | |
| ("Build your own `Regex Engine`"), primarily Russ Cox's | |
| *[Regular Expression Matching Can Be Simple And Fast](https://swtch.com/~rsc/regexp/regexp1.html)*. | |
| ## The idea | |
| Most popular regex engines (Perl, Python, Ruby, Java, PCRE) simulate an | |
| NFA by *backtracking*: guess a path, and retry on failure. On patterns | |
| like `a?a?a?aaa` that means trying all 2^n combinations — Perl needs | |
| **60+ seconds** to match a 29-character string. | |
| This engine instead simulates *all* NFA paths in parallel, tracking the | |
| set of reachable states one input character at a time (Thompson's 1968 | |
| algorithm). Matching is **O(m·n)** worst case for pattern length m and | |
| text length n. There are no pathological inputs. | |
| ``` | |
| infix pattern --re2post--> postfix --post2nfa--> NFA --pump--> match? | |
| (explicit '.' concat) (Thompson construction) | |
| ``` | |
| ## Syntax | |
| | construct | meaning | | |
| |---|---| | |
| | `abc` | literal characters match themselves | | |
| | `e1 e2` | concatenation | | |
| | `e1\|e2` | alternation | | |
| | `e*` | zero or more | | |
| | `e+` | one or more | | |
| | `e?` | zero or one | | |
| | `(e)` | grouping | | |
| | `\` + metachar | literal metacharacter: `\* \+ \? \| \( \) \\` | | |
| | `.` | literal dot (no wildcard — see roadmap) | | |
| Precedence: `|` weakest, then concatenation, then `* + ?`. Matching is | |
| byte-oriented. | |
| ## Build & test | |
| ```sh | |
| make # builds ./regex, clean compile, zero warnings | |
| make test # 82-check correctness harness (fullmatch, search, bad patterns) | |
| make bench # pathological benchmark vs Python's re | |
| ``` | |
| ## Usage | |
| ```sh | |
| $ ./regex 'a(bb)+a' abbbba abba abbba | |
| abbbba: MATCH | |
| abba: MATCH | |
| abbba: NO MATCH | |
| $ ./regex -s 'colou?r' 'the colour blue' | |
| the colour blue: MATCH | |
| ``` | |
| Exit codes: `0` all matched, `1` some didn't, `2` usage/bad pattern. | |
| As a library (`src/regex.h`): | |
| ```c | |
| Regex *re = re_compile("(ab|cd)+e"); | |
| int m = re_fullmatch(re, "cdabe"); /* whole string */ | |
| int p = re_match(re, "cdabex"); /* prefix of string */ | |
| int s = re_search(re, "xxcdabexx"); /* anywhere in string */ | |
| re_free(re); | |
| ``` | |
| ## Benchmark | |
| `a?`^n`a`^n against `a`^n — the article's pathological case: | |
| | n | snapkitty-regex | python `re` | | |
| |---|---|---| | |
| | 10 | 0.0011s | 0.0000s | | |
| | 20 | 0.0010s | 0.0442s | | |
| | 24 | 0.0013s | 0.7139s | | |
| | 26 | 0.0014s | 3.0580s | | |
| | 500 | 0.0021s | (heat death of universe) | | |
| (The ~1ms floor on our side is process-spawn overhead, not matching.) | |
| ## What's hardened vs the article's reference code | |
| - **No fixed static buffers** — postfix output and the paren stack are | |
| sized from the input instead of `char buf[8000]` / `paren[100]`. | |
| - **Backslash escapes** for metacharacters. | |
| - **Literal dots** — a `.` in the pattern can't collide with the postfix | |
| concatenation operator anymore (this crashes the original). | |
| - **Real error paths** — malformed patterns and `malloc` failures return | |
| `NULL` instead of crashing; partial allocations unwind cleanly. | |
| - **Reusable, releasable** — compiled patterns are opaque `Regex*` | |
| values with `re_free`; the accept state and dedup generation are | |
| per-pattern, not globals. | |
| - **Prefix match + search** on top of full match. | |
| ## Roadmap | |
| - `.` wildcard / character classes `[a-z]` | |
| - Capture groups and submatch extraction | |
| - DFA / hybrid execution for very large inputs | |
| - Streaming matcher API | |
| --- | |
| ### 💼 Commercial License | |
| SnapKitty code is free and open under **AGPL-3.0** for open-source use. Building a commercial product or service? A **proprietary commercial license** from Snapkitty Collective LLC lets you ship this code without the AGPL's source-sharing and network-use obligations. | |
| **[→ Get a commercial license](mailto:A.parr@belespritdaccord.uk?subject=Commercial%20license:%20snapkitty-regex)** · A.parr@belespritdaccord.uk | |