HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
rust-lang
regex
Rust2015–2026
rust-lang / regex

regex

An implementation of regular expressions for Rust. This implementation uses finite automata and guarantees linear time matching on all inputs.

39Distinct people
78Mentions
0Explicit recommenders
4.1KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

An implementation of regular expressions for Rust. This implementation uses finite automata and guarantees linear time matching on all inputs.

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

Mentioned in the same Hacker News threads. That is not proof they are substitutes.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 7:56:55 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year78 dated mentions

Observed mentions: 2015-01-15 13:24:18 UTC to 2026-02-20 01:45:45 UTC.

0510152015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 4 mentions; 0 submissions, 4 comments20152016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 11 mentions; 1 submissions, 10 comments2017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 14 mentions; 1 submissions, 13 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 7 mentions; 1 submissions, 6 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 7 mentions; 1 submissions, 6 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 5 mentions; 1 submissions, 4 comments20202021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 8 mentions; 0 submissions, 8 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 7 mentions; 0 submissions, 7 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 8 mentions; 2 submissions, 6 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC404
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC11110
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC14113
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC716
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC716
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC514
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC808
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC707
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC826
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC303
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC303
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC101

What Hacker News says

11 sources
Some other details on GNU grep's performance: * The Boyer-Moore algorithm it uses has a skip loop, which is used to quickly search for the last byte in the needle before trying to do more checking. Specifically, the skip loop is implemented with memchr, which can be found in your libc and probably compiles down to SIMD instructions. (The trick here isn't actually skipping bytes, but processing many bytes in a single loop iteration.) This optimization works well in the common case, but can slow things down a bit if your skip byte is really common in the haystack. * When a pattern consists of an alternation of literals, like, `abc|mno|xyz`, then it uses an algorithm based on Commentz-Walter, which you can think of as a hybrid between Aho-Corasick and Boyer-Moore. That is, you get the byte skipping of Boyer-Moore even though you're searching
Read the rest
for multiple patterns. The performance of Commentz-Walter degrades as the number of patterns increases because there's fewer opportunities for meaningful skips. Nevertheless, small/short alternations are probably the common case with GNU grep. (The state of the art has actually improved for this specific case and GNU grep could probably benefit. Specifically, the Hyperscan folks over at Intel have some really cool SIMD algorithms for matching multiple patterns. I implemented one here (the comments include a description with examples): https://github.com/rust-lang-nursery/regex/blob/master/src/s...) * The actual regex engine is a lazy DFA (similar to RE2) in that its states are computed on-demand as needed. That is, some parts of the DFA that aren't used are never computed at all. If the DFA gets too big in memory, the existing states are dropped and re-computed as needed. In this way, GNU grep gets the performance of a DFA while preserving linear time matching. (At most one new DFA state is computed for each byte of input.) The inner DFA loop is unrolled. * To re-emphazie a point from the post: avoiding line-by-line matching is critical. This makes it much easier to extract literals from a pattern. For example, if your pattern is `\w+foobar\d+`, then GNU grep can still search for `foobar` because it can make an assumption that its haystack is generally a very small slice of the entire search space (i.e., a single line). This type of optimization is much harder to pull off in a general purpose regex engine. A general purpose regex engine might limit itself to looking for prefix or suffix literals only. * GNU grep really doesn't do all that well for multi-byte encodings. e.g., The time difference between `LC_ALL=C egrep -c '\w{5}'` and `LC_ALL=en_US.UTF-8 egrep -c '\w{5}'` on a large file is quite dramatic. (~3 seconds vs ~52 seconds for a ~2GB mostly-ASCII file that is warm in my page cache.) There's really no need for this slow down if you can bake UTF-8 decoding into your DFA (RE2 does this). However, you then lose the ability to `grep` over other character encodings without transcoding them to UTF-8 first. (In fact, GNU grep may be doing this transcoding step today anyway, so maybe baking UTF-8 into your DFA would be a strictly better solution since it would be much faster on a much larger number of inputs, but probably not slower than any inputs. However, I'm not terribly familiar with this part of GNU grep, so I could have this wrong.)
In Why GNU grep is fast (2010)
> Do you mean the program became relatively slower because of changes you've made to the regex crate? Yes. The underlying reasoning is complex. When the regex crate got a lazy DFA (similar to the one used by RE2), the vast majority of regexes got significantly faster. Some got slower. This one in particular from regex-dna: >[^\n]*\n|\n Before the lazy DFA, compile time analysis would notice that all matches either start with `>` or `\n` and do a fast prefix scan for them. Each match of `>` or `\n` represents a candidate for a match. Candidates were then verified using something similar to the Thompson NFA, which is generally pretty slow, but the prefix scanning reduced the amount of work required considerably. Once the lazy DFA was added, the prefix scanning was still used, but the lazy DFA was used to verify candidates. It's faster
Read the rest
in general by a lot, but, the lazy DFA requires two scans of the candidate: one to find the end position and another to find the start position. That extra scan made processing this regex (on the regex-dna input) slightly slower. I've since fixed some of this by reducing a lot of the match overhead of the lazy DFA, so my hope is that it's back to par, but I haven't done any rigorous benchmarking to verify that. > Wasn't the program relatively faster because you wrote the regex crate to use Aho-Corasick for the matches required by the regex-dna task? Aho-Corasick is principally useful for the second phase of regex-dna, e.g., the regexes that look like `ag[act]gtaaa|tttac[agt]ct`. (In the last phase, all the regexes are just single byte literals, so neither Aho-Corasick nor the regex engine should ever be used.) Performance here should stay the same. On that note, I have a new nightly-only algorithm called Teddy that uses SIMD[1] (which replaces the use of Aho-Corasick for those regexes) and is a bit faster. I got the algorithm from the Hyperscan[2] project, which also does extensive literal analysis to speed up regexes. To clarify, this optimization is generally useful because a lot of regexes in the wild have prefix literals. Even something like `(?i:foo)\s+bar` can benefit from it, since `(?i:foo)` expands to FOO, FOo, FoO, Foo, fOO, fOo, foO, foo, which can of course be used with Aho-Corasick (and also my new SIMD algorithm). One also must wonder how well a C program using PCRE2's JIT would fair on the benchmarks game. From my experience, it would probably be near the top. It's quite fast! [1] - https://github.com/rust-lang-nursery/regex/blob/master/src/s... [2] - https://github.com/01org/hyperscan
In Why Rust for Low-Level Linux Programming?
The benchmarks aren't quite ready to be widely disseminated yet. With that said, I do record benchmarks from time to time in the repo to track progress, which you can see here: https://github.com/rust-lang-nursery/regex/tree/master/bench... --- You'll have to do the comparison yourself though. There is some analysis---only for Rust's regex engine---with the definition of the benchmarks themselves: https://github.com/rust-lang-nursery/regex/blob/master/bench... (If you fish around there, you'll also see how everything is wired up.) My plan at the moment is to publish something more comprehensive, but it will take time. And yes, the benchmarks you linked are not only outdated, but misleading, and parts of the conclusion I do not agree with. It also doesn't include PCRE2, which is very fast.
In Go bindings to Rust's regex engine
Regex::new has these tools at its disposal: Pike VM (NFA), backtracking (NFA), DFA (online), DFA (offline), Boyer-Moore The plugin has these tools at its disposal: Pike VM. But yeah, killercup is correct. The DFA (online) is one of the bigger reasons. But the offline DFA and Boyer-Moore are probably just as important. You might glean more information from my hacking guide: https://github.com/rust-lang-nursery/regex/blob/master/HACKI...
In Go bindings to Rust's regex engine
No, it can't happen at all. After processing the first state that visits all states on input i, all subsequent states explored in input i stop before traversing states that have already been visited. Since all states have already been visited, each state after the first on input i can be dismissed in constant time. Given that one can check whether a state has been visited in constant time, this is still just linear, not quadratic. Let's just look at code already. Here's the loop over states at input i: https://github.com/rust-lang-nursery/regex/blob/master/src/n... If we match a character at input i, then we follow epsilon transitions: https://github.com/rust-lang-nursery/regex/blob/master/src/n... If we visit a state that we've already seen, skip it: https://github.com/rust-lang-nursery/regex/blob/master/src/n... If that first state visi
Read the rest
ts all states, then `nlist` (which is maintained while following all states at any position in the input) will contain all states. In each subsequent iteration (line 165), even if the state wants to visit all states, it will be immediately stopped at the first check in line 300. No additional states for that state are followed.
In LL and LR in Context: Why Parsing Tools Are Hard (2013)
Rust's very own regexes should be besting PCRE now, even when PCRE's JIT is enabled. There are some benchmarks on the PR: https://github.com/rust-lang-nursery/regex/pull/164#issuecom... Also, FYI, but the rejit in the GP's benchmark link is not the same rejit in the OP. The rejit in the benchmark in the GP is actually based off of Russ Cox's articles. (It uses automata and doesn't support backreferences.) The places where PCRE is still winning come down to these things (I think): * Use of SIMD instructions with literal prefixes that have a small number of common leading bytes (greater than 1). I suspect this is what's going on with the "medium" benchmarks. I think the `jetscii` crate would help here, but it's only usable on the nightlies. * PCRE appears to be detecting a literal prefix of `\n` when the regex starts with `^` in multi-line
Read the rest
mode. (The sherlock::line_boundary_sherlock_holmes benchmark.) We could do this too---I just haven't yet. * The sherlock::word_ending_n benchmark has a word boundary, which the lazy DFA in Rust's regex library doesn't support. (It will be hard to improve here unfortunately.) * In general, I think PCRE probably has less overhead per match, which I haven't worked on too much. (For one, every search requires acquiring and quickly releasing a mutex in Rust's library. All I really need to do is push/pop from a stack, so I bet we could avoid the mutex.) On the rest of the regexes, Rust's library is either competitive or completely smashes PCRE in throughput. There are even a few benchmarks that I had to omit because PCRE was too slow. These are strong words, so my goodness, do I hope I'm benchmarking PCRE right! :P And this was all work done based on what Russ Cox wrote. Actual benchmark code is here: https://github.com/rust-lang-nursery/regex/blob/master/bench...
In Rejit: a work-in-progress JIT-powered regex engine

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.