Struct Regex
struct Regex { ... }
A regex matcher that works by composing several other regex matchers automatically.
In effect, a meta regex papers over a lot of the quirks or performance problems in each of the regex engines in this crate. Its goal is to provide an infallible and simple API that "just does the right thing" in the common case.
A meta regex is the implementation of a Regex in the regex crate.
Indeed, the regex crate API is essentially just a light wrapper over
this type. This includes the regex crate's RegexSet API!
Composition
This is called a "meta" matcher precisely because it uses other regex matchers to provide a convenient high level regex API. Here are some examples of how other regex matchers are composed:
- When calling
Regex::captures, instead of immediately running a slower but more capable regex engine like thePikeVM, the meta regex engine will usually first look for the bounds of a match with a higher throughput regex engine like a lazy DFA. Only when a match is found is a slower engine likePikeVMused to find the matching span for each capture group. - While higher throughout engines like the lazy DFA cannot handle Unicode word boundaries in general, they can still be used on pure ASCII haystacks by pretending that Unicode word boundaries are just plain ASCII word boundaries. However, if a haystack is not ASCII, the meta regex engine will automatically switch to a (possibly slower) regex engine that supports Unicode word boundaries in general.
- In some cases where a regex pattern is just a simple literal or a small set of literals, an actual regex engine won't be used at all. Instead, substring or multi-substring search algorithms will be employed.
There are many other forms of composition happening too, but the above should give a general idea. In particular, it may perhaps be surprising that multiple regex engines might get executed for a single search. That is, the decision of what regex engine to use is not just based on the pattern, but also based on the dynamic execution of the search itself.
The primary reason for this composition is performance. The fundamental tension is that the faster engines tend to be less capable, and the more capable engines tend to be slower.
Note that the forms of composition that are allowed are determined by
compile time crate features and configuration. For example, if the hybrid
feature isn't enabled, or if Config::hybrid has been disabled, then the
meta regex engine will never use a lazy DFA.
Synchronization and cloning
Most of the regex engines in this crate require some kind of mutable
"scratch" space to read and write from while performing a search. Since
a meta regex composes these regex engines, a meta regex also requires
mutable scratch space. This scratch space is called a Cache.
Most regex engines also usually have a read-only component, typically
a Thompson NFA.
In order to make the Regex API convenient, most of the routines hide
the fact that a Cache is needed at all. To achieve this, a memory
pool is used internally to retrieve Cache
values in a thread safe way that also permits reuse. This in turn implies
that every such search call requires some form of synchronization. Usually
this synchronization is fast enough to not notice, but in some cases, it
can be a bottleneck. This typically occurs when all of the following are
true:
- The same
Regexis shared across multiple threads simultaneously, usually via autil::lazy::Lazyor something similar from theonce_cellorlazy_staticcrates. - The primary unit of work in each thread is a regex search.
- Searches are run on very short haystacks.
This particular case can lead to high contention on the pool used by a
Regex internally, which can in turn increase latency to a noticeable
effect. This cost can be mitigated in one of the following ways:
- Use a distinct copy of a
Regexin each thread, usually by cloning it. Cloning aRegexdoes not do a deep copy of its read-only component. But it does lead to eachRegexhaving its own memory pool, which in turn eliminates the problem of contention. In general, this technique should not result in any additional memory usage when compared to sharing the sameRegexacross multiple threads simultaneously. - Use lower level APIs, like
Regex::search_with, which permit passing aCacheexplicitly. In this case, it is up to you to determine how best to provide aCache. For example, you might put aCachein thread-local storage if your use case allows for it.
Overall, this is an issue that happens rarely in practice, but it can happen.
Warning: spin-locks may be used in alloc-only mode
When this crate is built without the std feature and the high level APIs
on a Regex are used, then a spin-lock will be used to synchronize access
to an internal pool of Cache values. This may be undesirable because
a spin-lock is effectively impossible to implement correctly in user
space. That is, more concretely, the spin-lock could
result in a deadlock.
If one wants to avoid the use of spin-locks when the std feature is
disabled, then you must use APIs that accept a Cache value explicitly.
For example, Regex::search_with.
Example
use Regex;
let re = new?;
assert!;
# Ok::
Example: anchored search
This example shows how to use Input::anchored to run an anchored
search, even when the regex pattern itself isn't anchored. An anchored
search guarantees that if a match is found, then the start offset of the
match corresponds to the offset at which the search was started.
use ;
let re = new?;
let input = new.range.anchored;
// The offsets are in terms of the original haystack.
assert_eq!;
// Notice that no match occurs here, because \b still takes the
// surrounding context into account, even if it means looking back
// before the start of your search.
let hay = "xxfoo xx";
let input = new.range.anchored;
assert_eq!;
// Indeed, you cannot achieve the above by simply slicing the
// haystack itself, since the regex engine can't see the
// surrounding context. This is why 'Input' permits setting
// the bounds of a search!
let input = new.anchored;
// WRONG!
assert_eq!;
# Ok::
Example: earliest search
This example shows how to use Input::earliest to run a search that
might stop before finding the typical leftmost match.
use ;
let re = new?;
let input = new.earliest;
assert_eq!;
// Note that "earliest" isn't really a match semantic unto itself.
// Instead, it is merely an instruction to whatever regex engine
// gets used internally to quit as soon as it can. For example,
// this regex uses a different search technique, and winds up
// producing a different (but valid) match!
let re = new?;
let input = new.earliest;
assert_eq!;
# Ok::
Example: change the line terminator
This example shows how to enable multi-line mode by default and change the line terminator to the NUL byte:
use ;
let re = builder
.syntax
.configure
.build?;
let hay = "\x00foo\x00";
assert_eq!;
# Ok::
Implementations
impl Regex
fn new(pattern: &str) -> Result<Regex, BuildError>Builds a
Regexfrom a single pattern string using the default configuration.If there was a problem parsing the pattern or a problem turning it into a regex matcher, then an error is returned.
If you want to change the configuration of a
Regex, use aBuilderwith aConfig.Example
use ; let re = new?; let hay = "\r\nfoo\r\n"; assert_eq!; # Ok::fn new_many<P: AsRef<str>>(patterns: &[P]) -> Result<Regex, BuildError>Builds a
Regexfrom many pattern strings using the default configuration.If there was a problem parsing any of the patterns or a problem turning them into a regex matcher, then an error is returned.
If you want to change the configuration of a
Regex, use aBuilderwith aConfig.Example: simple lexer
This simplistic example leverages the multi-pattern support to build a simple little lexer. The pattern ID in the match tells you which regex matched, which in turn might be used to map back to the "type" of the token returned by the lexer.
use ; let re = new_many?; let haystack = "fn is_boss(bruce: i32, springsteen: String) -> bool;"; let matches: = re.find_iter.collect; assert_eq!; # Ok::One can write a lexer like the above using a regex like
(?P<space>[[:space:]])|(?P<ident>[A-Za-z0-9][A-Za-z0-9_]+)|..., but then you need to ask whether capture group matched to determine which branch in the regex matched, and thus, which token the match corresponds to. In contrast, the above example includes the pattern ID in the match. There's no need to use capture groups at all.Example: finding the pattern that caused an error
When a syntax error occurs, it is possible to ask which pattern caused the syntax error.
use ; let err = new_many.unwrap_err; assert_eq!;Example: zero patterns is valid
Building a regex with zero patterns results in a regex that never matches anything. Because this routine is generic, passing an empty slice usually requires a turbo-fish (or something else to help type inference).
use ; let re = ?; assert_eq!; # Ok::fn config() -> ConfigReturn a default configuration for a
Regex.This is a convenience routine to avoid needing to import the
Configtype when customizing the construction of aRegex.Example: lower the NFA size limit
In some cases, the default size limit might be too big. The size limit can be lowered, which will prevent large regex patterns from compiling.
# if cfg! // miri takes too long use Regex; let result = builder .configure // Not even 20KB is enough to build a single large Unicode class! .build; assert!; # Ok::fn builder() -> BuilderReturn a builder for configuring the construction of a
Regex.This is a convenience routine to avoid needing to import the
Buildertype in common cases.Example: change the line terminator
This example shows how to enable multi-line mode by default and change the line terminator to the NUL byte:
use ; let re = builder .syntax .configure .build?; let hay = "\x00foo\x00"; assert_eq!; # Ok::
impl Regex
fn is_match<'h, I: Into<Input<'h>>>(self: &Self, input: I) -> boolReturns true if and only if this regex matches the given haystack.
This routine may short circuit if it knows that scanning future input will never lead to a different result. (Consider how this might make a difference given the regex
a+on the haystackaaaaaaaaaaaaaaa. This routine may stop after it sees the firsta, but routines likefindneed to continue searching because+is greedy by default.)Example
use Regex; let re = new?; assert!; assert!; # Ok::Example: consistency with search APIs
is_matchis guaranteed to returntruewheneverfindreturns a match. This includes searches that are executed entirely within a codepoint:use ; let re = new?; // This doesn't match because the default configuration bans empty // matches from splitting a codepoint. assert!; assert_eq!; # Ok::Notice that when UTF-8 mode is disabled, then the above reports a match because the restriction against zero-width matches that split a codepoint has been lifted:
use ; let re = builder .configure .build?; assert!; assert_eq!; # Ok::A similar idea applies when using line anchors with CRLF mode enabled, which prevents them from matching between a
\rand a\n.use ; let re = new?; assert!; // A regular line anchor, which only considers \n as a // line terminator, will match. let re = new?; assert!; # Ok::fn find<'h, I: Into<Input<'h>>>(self: &Self, input: I) -> Option<Match>Executes a leftmost search and returns the first match that is found, if one exists.
Example
use ; let re = new?; assert_eq!; # Ok::fn captures<'h, I: Into<Input<'h>>>(self: &Self, input: I, caps: &mut Captures)Executes a leftmost forward search and writes the spans of capturing groups that participated in a match into the provided
Capturesvalue. If no match was found, thenCaptures::is_matchis guaranteed to returnfalse.Example
use ; let re = new?; let mut caps = re.create_captures; re.captures; assert!; assert_eq!; assert_eq!; assert_eq!; # Ok::fn find_iter<'r, 'h, I: Into<Input<'h>>>(self: &'r Self, input: I) -> FindMatches<'r, 'h>Returns an iterator over all non-overlapping leftmost matches in the given haystack. If no match exists, then the iterator yields no elements.
Example
use ; let re = new?; let haystack = "foo1 foo12 foo123"; let matches: = re.find_iter.collect; assert_eq!; # Ok::fn captures_iter<'r, 'h, I: Into<Input<'h>>>(self: &'r Self, input: I) -> CapturesMatches<'r, 'h>Returns an iterator over all non-overlapping
Capturesvalues. If no match exists, then the iterator yields no elements.This yields the same matches as
Regex::find_iter, but it includes the spans of all capturing groups that participate in each match.Tip: See
util::iter::Searcherfor how to correctly iterate over all matches in a haystack while avoiding the creation of a newCapturesvalue for every match. (Which you are forced to do with anIterator.)Example
use ; let re = new?; let haystack = "foo1 foo12 foo123"; let matches: = re .captures_iter // The unwrap is OK since 'numbers' matches if the pattern matches. .map .collect; assert_eq!; # Ok::fn split<'r, 'h, I: Into<Input<'h>>>(self: &'r Self, input: I) -> Split<'r, 'h>Returns an iterator of spans of the haystack given, delimited by a match of the regex. Namely, each element of the iterator corresponds to a part of the haystack that isn't matched by the regular expression.
Example
To split a string delimited by arbitrary amounts of spaces or tabs:
use Regex; let re = new?; let hay = "a b \t c\td e"; let fields: = re.split.map.collect; assert_eq!; # Ok::Example: more cases
Basic usage:
use Regex; let re = new?; let hay = "Mary had a little lamb"; let got: = re.split.map.collect; assert_eq!; let re = new?; let hay = ""; let got: = re.split.map.collect; assert_eq!; let re = new?; let hay = "lionXXtigerXleopard"; let got: = re.split.map.collect; assert_eq!; let re = new?; let hay = "lion::tiger::leopard"; let got: = re.split.map.collect; assert_eq!; # Ok::If a haystack contains multiple contiguous matches, you will end up with empty spans yielded by the iterator:
use Regex; let re = new?; let hay = "XXXXaXXbXc"; let got: = re.split.map.collect; assert_eq!; let re = new?; let hay = "(///)"; let got: = re.split.map.collect; assert_eq!; # Ok::Separators at the start or end of a haystack are neighbored by empty spans.
use Regex; let re = new?; let hay = "010"; let got: = re.split.map.collect; assert_eq!; # Ok::When the empty string is used as a regex, it splits at every valid UTF-8 boundary by default (which includes the beginning and end of the haystack):
use Regex; let re = new?; let hay = "rust"; let got: = re.split.map.collect; assert_eq!; // Splitting by an empty string is UTF-8 aware by default! let re = new?; let hay = "☃"; let got: = re.split.map.collect; assert_eq!; # Ok::But note that UTF-8 mode for empty strings can be disabled, which will then result in a match at every byte offset in the haystack, including between every UTF-8 code unit.
use Regex; let re = builder .configure .build?; let hay = "☃".as_bytes; let got: = re.split.map.collect; assert_eq!; # Ok::Contiguous separators (commonly shows up with whitespace), can lead to possibly surprising behavior. For example, this code is correct:
use Regex; let re = new?; let hay = " a b c"; let got: = re.split.map.collect; assert_eq!; # Ok::It does not give you
["a", "b", "c"]. For that behavior, you'd want to match contiguous space characters:use Regex; let re = new?; let hay = " a b c"; let got: = re.split.map.collect; // N.B. This does still include a leading empty span because ' +' // matches at the beginning of the haystack. assert_eq!; # Ok::fn splitn<'r, 'h, I: Into<Input<'h>>>(self: &'r Self, input: I, limit: usize) -> SplitN<'r, 'h>Returns an iterator of at most
limitspans of the haystack given, delimited by a match of the regex. (Alimitof0will return no spans.) Namely, each element of the iterator corresponds to a part of the haystack that isn't matched by the regular expression. The remainder of the haystack that is not split will be the last element in the iterator.Example
Get the first two words in some haystack:
# if cfg! // miri takes too long use Regex; let re = new.unwrap; let hay = "Hey! How are you?"; let fields: = re.splitn.map.collect; assert_eq!; # Ok::Examples: more cases
use Regex; let re = new?; let hay = "Mary had a little lamb"; let got: = re.splitn.map.collect; assert_eq!; let re = new?; let hay = ""; let got: = re.splitn.map.collect; assert_eq!; let re = new?; let hay = "lionXXtigerXleopard"; let got: = re.splitn.map.collect; assert_eq!; let re = new?; let hay = "lion::tiger::leopard"; let got: = re.splitn.map.collect; assert_eq!; let re = new?; let hay = "abcXdef"; let got: = re.splitn.map.collect; assert_eq!; let re = new?; let hay = "abcdef"; let got: = re.splitn.map.collect; assert_eq!; let re = new?; let hay = "abcXdef"; let got: = re.splitn.map.collect; assert!; # Ok::
impl Regex
fn create_captures(self: &Self) -> CapturesCreates a new object for recording capture group offsets. This is used in search APIs like
Regex::capturesandRegex::search_captures.This is a convenience routine for
Captures::all(re.group_info().clone()). Callers may build other types ofCapturesvalues that record less information (and thus require less work from the regex engine) usingCaptures::matchesandCaptures::empty.Example
This shows some alternatives to [
Regex::create_captures]:use ; let re = new?; // This is equivalent to Regex::create_captures. It stores matching // offsets for all groups in the regex. let mut all = all; re.captures; assert_eq!; assert_eq!; assert_eq!; // In this version, we only care about the implicit groups, which // means offsets for the explicit groups will be unavailable. It can // sometimes be faster to ask for fewer groups, since the underlying // regex engine needs to do less work to keep track of them. let mut matches = matches; re.captures; // We still get the overall match info. assert_eq!; // But now the explicit groups are unavailable. assert_eq!; assert_eq!; // Finally, in this version, we don't ask to keep track of offsets for // *any* groups. All we get back is whether a match occurred, and if // so, the ID of the pattern that matched. let mut empty = empty; re.captures; // it's a match! assert!; // for pattern ID 0 assert_eq!; // Match offsets are unavailable. assert_eq!; // And of course, explicit groups are unavailable too. assert_eq!; assert_eq!; # Ok::fn create_cache(self: &Self) -> CacheCreates a new cache for use with lower level search APIs like
Regex::search_with.The cache returned should only be used for searches for this
Regex. If you want to reuse the cache for anotherRegex, then you must callCache::resetwith thatRegex.This is a convenience routine for
Cache::new.Example
use ; let re = new?; let mut cache = re.create_cache; let input = new; assert_eq!; # Ok::fn pattern_len(self: &Self) -> usizeReturns the total number of patterns in this regex.
The standard
Regex::newconstructor always results in aRegexwith a single pattern, butRegex::new_manypermits building a multi-pattern regex.A
Regexguarantees that the maximum possiblePatternIDreturned in any match isRegex::pattern_len() - 1. In the case where the number of patterns is0, a match is impossible.Example
use Regex; let re = new?; assert_eq!; let re = ?; assert_eq!; let re = new_many?; assert_eq!; # Ok::fn captures_len(self: &Self) -> usizeReturns the total number of capturing groups.
This includes the implicit capturing group corresponding to the entire match. Therefore, the minimum value returned is
1.Example
This shows a few patterns and how many capture groups they have.
use Regex; let len = ; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; # Ok::Example: multiple patterns
This routine also works for multiple patterns. The total number is the sum of the capture groups of each pattern.
use Regex; let len = ; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; # Ok::fn static_captures_len(self: &Self) -> Option<usize>Returns the total number of capturing groups that appear in every possible match.
If the number of capture groups can vary depending on the match, then this returns
None. That is, a value is only returned when the number of matching groups is invariant or "static."Note that like
Regex::captures_len, this does include the implicit capturing group corresponding to the entire match. Therefore, when a non-None value is returned, it is guaranteed to be at least1. Stated differently, a return value ofSome(0)is impossible.Example
This shows a few cases where a static number of capture groups is available and a few cases where it is not.
use Regex; let len = ; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; # Ok::Example: multiple patterns
This property extends to regexes with multiple patterns as well. In order for their to be a static number of capture groups in this case, every pattern must have the same static number.
use Regex; let len = ; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; # Ok::fn group_info(self: &Self) -> &GroupInfoReturn information about the capture groups in this
Regex.A
GroupInfois an immutable object that can be cheaply cloned. It is responsible for maintaining a mapping between the capture groups in the concrete syntax of zero or more regex patterns and their internal representation used by some of the regex matchers. It is also responsible for maintaining a mapping between the name of each group (if one exists) and its corresponding group index.A
GroupInfois ultimately what is used to build aCapturesvalue, which is some mutable space where group offsets are stored as a result of a search.Example
This shows some alternatives to [
Regex::create_captures]:use ; let re = new?; // This is equivalent to Regex::create_captures. It stores matching // offsets for all groups in the regex. let mut all = all; re.captures; assert_eq!; assert_eq!; assert_eq!; // In this version, we only care about the implicit groups, which // means offsets for the explicit groups will be unavailable. It can // sometimes be faster to ask for fewer groups, since the underlying // regex engine needs to do less work to keep track of them. let mut matches = matches; re.captures; // We still get the overall match info. assert_eq!; // But now the explicit groups are unavailable. assert_eq!; assert_eq!; // Finally, in this version, we don't ask to keep track of offsets for // *any* groups. All we get back is whether a match occurred, and if // so, the ID of the pattern that matched. let mut empty = empty; re.captures; // it's a match! assert!; // for pattern ID 0 assert_eq!; // Match offsets are unavailable. assert_eq!; // And of course, explicit groups are unavailable too. assert_eq!; assert_eq!; # Ok::fn get_config(self: &Self) -> &ConfigReturns the configuration object used to build this
Regex.If no configuration object was explicitly passed, then the configuration returned represents the default.
fn is_accelerated(self: &Self) -> boolReturns true if this regex has a high chance of being "accelerated."
The precise meaning of "accelerated" is specifically left unspecified, but the general meaning is that the search is a high likelihood of running faster than a character-at-a-time loop inside a standard regex engine.
When a regex is accelerated, it is only a probabilistic claim. That is, just because the regex is believed to be accelerated, that doesn't mean it will definitely execute searches very fast. Similarly, if a regex is not accelerated, that is also a probabilistic claim. That is, a regex for which
is_acceleratedreturnsfalsecould still run searches more quickly than a regex for whichis_acceleratedreturnstrue.Whether a regex is marked as accelerated or not is dependent on implementations details that may change in a semver compatible release. That is, a regex that is accelerated in a
x.y.1release might not be accelerated in ax.y.2release.Basically, the value of acceleration boils down to a hedge: a hodge podge of internal heuristics combine to make a probabilistic guess that this regex search may run "fast." The value in knowing this from a caller's perspective is that it may act as a signal that no further work should be done to accelerate a search. For example, a grep-like tool might try to do some extra work extracting literals from a regex to create its own heuristic acceleration strategies. But it might choose to defer to this crate's acceleration strategy if one exists. This routine permits querying whether such a strategy is active for a particular regex.
Example
use Regex; // A simple literal is very likely to be accelerated. let re = new?; assert!; // A regex with no literals is likely to not be accelerated. let re = new?; assert!; # Ok::fn memory_usage(self: &Self) -> usizeReturn the total approximate heap memory, in bytes, used by this
Regex.Note that currently, there is no high level configuration for setting a limit on the specific value returned by this routine. Instead, the following routines can be used to control heap memory at a bit of a lower level:
Config::nfa_size_limitcontrols how big any of the NFAs are allowed to be.Config::onepass_size_limitcontrols how big the one-pass DFA is allowed to be.Config::hybrid_cache_capacitycontrols how much memory the lazy DFA is permitted to allocate to store its transition table.Config::dfa_size_limitcontrols how big a fully compiled DFA is allowed to be.Config::dfa_state_limitcontrols the conditions under which the meta regex engine will even attempt to build a fully compiled DFA.
impl Regex
fn search_with(self: &Self, cache: &mut Cache, input: &Input<'_>) -> Option<Match>This is like
Regex::search, but requires the caller to explicitly pass aCache.Why pass a
Cacheexplicitly?Passing a
Cacheexplicitly will bypass the use of an internal memory pool used byRegexto get aCachefor a search. The use of this pool can be slower in some cases when aRegexis used from multiple threads simultaneously. Typically, performance only becomes an issue when there is heavy contention, which in turn usually only occurs when each thread's primary unit of work is a regex search on a small haystack.Example
use ; let re = new?; let mut cache = re.create_cache; let input = new; assert_eq!; # Ok::fn search_half_with(self: &Self, cache: &mut Cache, input: &Input<'_>) -> Option<HalfMatch>This is like
Regex::search_half, but requires the caller to explicitly pass aCache.Why pass a
Cacheexplicitly?Passing a
Cacheexplicitly will bypass the use of an internal memory pool used byRegexto get aCachefor a search. The use of this pool can be slower in some cases when aRegexis used from multiple threads simultaneously. Typically, performance only becomes an issue when there is heavy contention, which in turn usually only occurs when each thread's primary unit of work is a regex search on a small haystack.Example
use ; let re = new?; let mut cache = re.create_cache; let input = new; assert_eq!; # Ok::fn search_captures_with(self: &Self, cache: &mut Cache, input: &Input<'_>, caps: &mut Captures)This is like
Regex::search_captures, but requires the caller to explicitly pass aCache.Why pass a
Cacheexplicitly?Passing a
Cacheexplicitly will bypass the use of an internal memory pool used byRegexto get aCachefor a search. The use of this pool can be slower in some cases when aRegexis used from multiple threads simultaneously. Typically, performance only becomes an issue when there is heavy contention, which in turn usually only occurs when each thread's primary unit of work is a regex search on a small haystack.Example: specific pattern search
This example shows how to build a multi-pattern
Regexthat permits searching for specific patterns.use ; let re = new_many?; let = ; let haystack = "foo123"; // Since we are using the default leftmost-first match and both // patterns match at the same starting position, only the first pattern // will be returned in this case when doing a search for any of the // patterns. let expected = Some; re.search_captures_with; assert_eq!; // But if we want to check whether some other pattern matches, then we // can provide its pattern ID. let expected = Some; let input = new .anchored; re.search_captures_with; assert_eq!; # Ok::Example: specifying the bounds of a search
This example shows how providing the bounds of a search can produce different results than simply sub-slicing the haystack.
# if cfg! // miri takes too long use ; let re = new?; let = ; let haystack = "foo123bar"; // Since we sub-slice the haystack, the search doesn't know about // the larger context and assumes that `123` is surrounded by word // boundaries. And of course, the match position is reported relative // to the sub-slice as well, which means we get `0..3` instead of // `3..6`. let expected = Some; let input = new; re.search_captures_with; assert_eq!; // But if we provide the bounds of the search within the context of the // entire haystack, then the search can take the surrounding context // into account. (And if we did find a match, it would be reported // as a valid offset into `haystack` instead of its sub-slice.) let expected = None; let input = new.range; re.search_captures_with; assert_eq!; # Ok::fn search_slots_with(self: &Self, cache: &mut Cache, input: &Input<'_>, slots: &mut [Option<NonMaxUsize>]) -> Option<PatternID>This is like
Regex::search_slots, but requires the caller to explicitly pass aCache.Why pass a
Cacheexplicitly?Passing a
Cacheexplicitly will bypass the use of an internal memory pool used byRegexto get aCachefor a search. The use of this pool can be slower in some cases when aRegexis used from multiple threads simultaneously. Typically, performance only becomes an issue when there is heavy contention, which in turn usually only occurs when each thread's primary unit of work is a regex search on a small haystack.Example
This example shows how to find the overall match offsets in a multi-pattern search without allocating a
Capturesvalue. Indeed, we can put our slots right on the stack.# if cfg! // miri takes too long use ; let re = new_many?; let mut cache = re.create_cache; let input = new; // We only care about the overall match offsets here, so we just // allocate two slots for each pattern. Each slot records the start // and end of the match. let mut slots = ; let pid = re.search_slots_with; assert_eq!; // The overall match offsets are always at 'pid * 2' and 'pid * 2 + 1'. // See 'GroupInfo' for more details on the mapping between groups and // slot indices. let slot_start = pid.unwrap.as_usize * 2; let slot_end = slot_start + 1; assert_eq!; assert_eq!; # Ok::fn which_overlapping_matches_with(self: &Self, cache: &mut Cache, input: &Input<'_>, patset: &mut PatternSet)This is like
Regex::which_overlapping_matches, but requires the caller to explicitly pass aCache.Passing a
Cacheexplicitly will bypass the use of an internal memory pool used byRegexto get aCachefor a search. The use of this pool can be slower in some cases when aRegexis used from multiple threads simultaneously. Typically, performance only becomes an issue when there is heavy contention, which in turn usually only occurs when each thread's primary unit of work is a regex search on a small haystack.Why pass a
Cacheexplicitly?Example
# if cfg! // miri takes too long use ; let patterns = &; let re = builder .configure .build_many?; let mut cache = re.create_cache; let input = new; let mut patset = new; re.which_overlapping_matches_with; let expected = vec!; let got: = patset.iter.map.collect; assert_eq!; # Ok::
impl Regex
fn search(self: &Self, input: &Input<'_>) -> Option<Match>Returns the start and end offset of the leftmost match. If no match exists, then
Noneis returned.This is like
Regex::findbut, but it accepts a concrete&Inputinstead of anInto<Input>.Example
use ; let re = new?; let input = new; assert_eq!; # Ok::fn search_half(self: &Self, input: &Input<'_>) -> Option<HalfMatch>Returns the end offset of the leftmost match. If no match exists, then
Noneis returned.This is distinct from
Regex::searchin that it only returns the end of a match and not the start of the match. Depending on a variety of implementation details, this may permit the regex engine to do less overall work. For example, if a DFA is being used to execute a search, then the start of a match usually requires running a separate DFA in reverse to the find the start of a match. If one only needs the end of a match, then the separate reverse scan to find the start of a match can be skipped. (Note that the reverse scan is avoided even when usingRegex::searchwhen possible, for example, in the case of an anchored search.)Example
use ; let re = new?; let input = new; assert_eq!; # Ok::fn search_captures(self: &Self, input: &Input<'_>, caps: &mut Captures)Executes a leftmost forward search and writes the spans of capturing groups that participated in a match into the provided
Capturesvalue. If no match was found, thenCaptures::is_matchis guaranteed to returnfalse.This is like
Regex::captures, but it accepts a concrete&Inputinstead of anInto<Input>.Example: specific pattern search
This example shows how to build a multi-pattern
Regexthat permits searching for specific patterns.use ; let re = new_many?; let mut caps = re.create_captures; let haystack = "foo123"; // Since we are using the default leftmost-first match and both // patterns match at the same starting position, only the first pattern // will be returned in this case when doing a search for any of the // patterns. let expected = Some; re.search_captures; assert_eq!; // But if we want to check whether some other pattern matches, then we // can provide its pattern ID. let expected = Some; let input = new .anchored; re.search_captures; assert_eq!; # Ok::Example: specifying the bounds of a search
This example shows how providing the bounds of a search can produce different results than simply sub-slicing the haystack.
# if cfg! // miri takes too long use ; let re = new?; let mut caps = re.create_captures; let haystack = "foo123bar"; // Since we sub-slice the haystack, the search doesn't know about // the larger context and assumes that `123` is surrounded by word // boundaries. And of course, the match position is reported relative // to the sub-slice as well, which means we get `0..3` instead of // `3..6`. let expected = Some; let input = new; re.search_captures; assert_eq!; // But if we provide the bounds of the search within the context of the // entire haystack, then the search can take the surrounding context // into account. (And if we did find a match, it would be reported // as a valid offset into `haystack` instead of its sub-slice.) let expected = None; let input = new.range; re.search_captures; assert_eq!; # Ok::fn search_slots(self: &Self, input: &Input<'_>, slots: &mut [Option<NonMaxUsize>]) -> Option<PatternID>Executes a leftmost forward search and writes the spans of capturing groups that participated in a match into the provided
slots, and returns the matching pattern ID. The contents of the slots for patterns other than the matching pattern are unspecified. If no match was found, thenNoneis returned and the contents ofslotsis unspecified.This is like
Regex::search, but it accepts a raw slots slice instead of aCapturesvalue. This is useful in contexts where you don't want or need to allocate aCaptures.It is legal to pass any number of slots to this routine. If the regex engine would otherwise write a slot offset that doesn't fit in the provided slice, then it is simply skipped. In general though, there are usually three slice lengths you might want to use:
- An empty slice, if you only care about which pattern matched.
- A slice with
pattern_len() * 2slots, if you only care about the overall match spans for each matching pattern. - A slice with
slot_len()slots, which permits recording match offsets for every capturing group in every pattern.
Example
This example shows how to find the overall match offsets in a multi-pattern search without allocating a
Capturesvalue. Indeed, we can put our slots right on the stack.# if cfg! // miri takes too long use ; let re = new_many?; let input = new; // We only care about the overall match offsets here, so we just // allocate two slots for each pattern. Each slot records the start // and end of the match. let mut slots = ; let pid = re.search_slots; assert_eq!; // The overall match offsets are always at 'pid * 2' and 'pid * 2 + 1'. // See 'GroupInfo' for more details on the mapping between groups and // slot indices. let slot_start = pid.unwrap.as_usize * 2; let slot_end = slot_start + 1; assert_eq!; assert_eq!; # Ok::fn which_overlapping_matches(self: &Self, input: &Input<'_>, patset: &mut PatternSet)Writes the set of patterns that match anywhere in the given search configuration to
patset. If multiple patterns match at the same position and thisRegexwas configured withMatchKind::Allsemantics, then all matching patterns are written to the given set.Unless all of the patterns in this
Regexare anchored, then generally speaking, this will scan the entire haystack.This search routine does not clear the pattern set. This gives some flexibility to the caller (e.g., running multiple searches with the same pattern set), but does make the API bug-prone if you're reusing the same pattern set for multiple searches but intended them to be independent.
If a pattern ID matched but the given
PatternSetdoes not have sufficient capacity to store it, then it is not inserted and silently dropped.Example
This example shows how to find all matching patterns in a haystack, even when some patterns match at the same position as other patterns. It is important that we configure the
RegexwithMatchKind::Allsemantics here, or else overlapping matches will not be reported.# if cfg! // miri takes too long use ; let patterns = &; let re = builder .configure .build_many?; let input = new; let mut patset = new; re.which_overlapping_matches; let expected = vec!; let got: = patset.iter.map.collect; assert_eq!; # Ok::
impl Clone for Regex
fn clone(self: &Self) -> Regex
impl Debug for Regex
fn fmt(self: &Self, f: &mut Formatter<'_>) -> Result
impl Freeze for Regex
impl RefUnwindSafe for Regex
impl Send for Regex
impl Sync for Regex
impl Unpin for Regex
impl UnsafeUnpin for Regex
impl UnwindSafe for Regex
impl<T> Any for Regex
fn type_id(self: &Self) -> TypeId
impl<T> Borrow for Regex
fn borrow(self: &Self) -> &T
impl<T> BorrowMut for Regex
fn borrow_mut(self: &mut Self) -> &mut T
impl<T> CloneToUninit for Regex
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8)
impl<T> From for Regex
fn from(t: T) -> TReturns the argument unchanged.
impl<T> ToOwned for Regex
fn to_owned(self: &Self) -> Tfn clone_into(self: &Self, target: &mut T)
impl<T, U> Into for Regex
fn into(self: Self) -> UCalls
U::from(self).That is, this conversion is whatever the implementation of
[From]<T> for Uchooses to do.
impl<T, U> TryFrom for Regex
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
impl<T, U> TryInto for Regex
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error>