pub struct RE2(/* private fields */);Expand description
High-level string search and replacement with a single pattern.
use re2::RE2;
let r: RE2 = "a(.+)f".parse()?;
let [m] = r.full_match_capturing("asdf").unwrap();
assert_eq!(m, "sd");Implementations§
Source§impl RE2
§RE2 = (pattern, options)
Basic components of RE2 objects. Self::quote_meta() is a common
utility method to construct pattern strings.
impl RE2
§RE2 = (pattern, options)
Basic components of RE2 objects. Self::quote_meta() is a common
utility method to construct pattern strings.
Sourcepub fn compile(pattern: &str, options: Options) -> Result<Self, CompileError>
pub fn compile(pattern: &str, options: Options) -> Result<Self, CompileError>
Compile an RE2 pattern.
A FromStr implementation is also provided which calls
this method with Options::default(), enabling the use of
str::parse():
use re2::{RE2, options::Options};
let r = RE2::compile("asdf".into(), Options::default())?;
assert!(r.full_match("asdf"));
let r2: RE2 = "asdf".parse()?;
assert_eq!(r, r2);The error contains the original pattern string as well as a description of the compile failure:
use re2::{RE2, error::*};
assert_eq!(
"a(sdf".parse::<RE2>().err().unwrap(),
CompileError {
message: "missing ): a(sdf".to_string(),
arg: "a(sdf".to_string(),
code: RE2ErrorCode::MissingParen,
},
);Sourcepub fn pattern(&self) -> &str
pub fn pattern(&self) -> &str
Extract the pattern string provided to the compiler.
let r: re2::RE2 = "asdf".parse()?;
assert_eq!(r.pattern(), "asdf");Sourcepub fn options(&self) -> Options
pub fn options(&self) -> Options
Extract the options object provided to the compiler.
use re2::{RE2, options::*};
let o: Options = CannedOptions::POSIX.into();
let r = RE2::compile("asdf".into(), o)?;
assert_eq!(o, r.options());
assert_ne!(o, Options::default());Sourcepub fn expensive_clone(&self) -> Self
pub fn expensive_clone(&self) -> Self
Create a new instance of this RE2 with the same semantics.
This method is largely intended for documentation purposes; Clone is
not implemented because of several performance reasons to re-use the
same instance, e.g. with an Arc.
The matching implementation may use a lazy NFA, which is partially constructed as it is matched against input strings, so it improves performance to use a reference to the same instance where possible, to avoid reconstructing the same NFA components. Upfront compilation of this NFA is also somewhat expensive in itself (even if less expensive than a DFA), and best to avoid repeating.
use re2::{RE2, options::*};
let o: Options = CannedOptions::POSIX.into();
let r = RE2::compile("asdf".into(), o)?;
assert_eq!(o, r.options());
assert_ne!(o, Options::default());
let r2 = r.expensive_clone();
assert_eq!(&r, &r2);Sourcepub fn quote_meta(pattern: &str) -> StringWrapper
pub fn quote_meta(pattern: &str) -> StringWrapper
Escape any metacharacters in pattern.
use re2::RE2;
let q = RE2::quote_meta("1.5-1.8?".into());
let r: RE2 = unsafe { q.as_view().as_str() }.parse()?;
assert_eq!(r"1\.5\-1\.8\?", r.pattern());
assert!(r.full_match("1.5-1.8?"));Note that literal patterns can be used instead in some cases:
use re2::{RE2, options::Options};
let o = Options { literal: true, ..Default::default() };
let r = RE2::compile("1.5-1.8?".into(), o)?;
assert_eq!("1.5-1.8?", r.pattern());
assert!(r.full_match("1.5-1.8?"));Source§impl RE2
§Matching
Matching methods tend to have a few variants:
impl RE2
§Matching
Matching methods tend to have a few variants:
- Methods with a
*_capturingsuffix will return a variable array of strings corresponding to matching capture groups. For these methods, requesting more groups than the result ofSelf::num_captures()will immediately returnNonewithout performing the search.
Self::match_routine() also returns a variable array of strings, but
presents a slightly different interface. It is the most general matching
entry point along with Self::match_no_captures() and is suitable for
building higher-level matching interfaces.
Sourcepub fn full_match(&self, text: &str) -> bool
pub fn full_match(&self, text: &str) -> bool
Match against text without capturing. Pattern must match entire string.
let r: re2::RE2 = "a.df".parse()?;
assert!(r.full_match("asdf"));
assert!(!r.full_match("asdfe"));
assert!(!r.full_match("basdf"));Sourcepub fn full_match_capturing<'a, const N: usize>(
&self,
text: &'a str,
) -> Option<[&'a str; N]>
pub fn full_match_capturing<'a, const N: usize>( &self, text: &'a str, ) -> Option<[&'a str; N]>
Match against text and return a subset of declared capture groups.
Pattern must match entire string.
let r: re2::RE2 = "a(.)d(f)".parse()?;
assert_eq!(2, r.num_captures());
let msg = "asdf";
// The 0 case still works, but just calls .full_match():
assert!(r.full_match_capturing::<0>(msg).is_some());
let [s1, s2] = r.full_match_capturing(msg).unwrap();
assert_eq!(s1, "s");
assert_eq!(s2, "f");
// The result isn't copied, it points to the same memory:
assert_eq!(s1.as_bytes().as_ptr(), msg[1..].as_bytes().as_ptr());
assert_eq!(s2.as_bytes().as_ptr(), msg[3..].as_bytes().as_ptr());Sourcepub fn partial_match(&self, text: &str) -> bool
pub fn partial_match(&self, text: &str) -> bool
Like Self::full_match(), except that the pattern may match a substring
of text.
let r: re2::RE2 = "a.df".parse()?;
assert!(r.partial_match("asdf"));
assert!(r.partial_match("asdfe"));
assert!(r.partial_match("basdf"));
assert!(!r.partial_match("ascf"));Sourcepub fn partial_match_capturing<'a, const N: usize>(
&self,
text: &'a str,
) -> Option<[&'a str; N]>
pub fn partial_match_capturing<'a, const N: usize>( &self, text: &'a str, ) -> Option<[&'a str; N]>
Match against text and return a subset of declared capture groups.
Like Self::full_match_capturing(), except that the pattern may match a
substring of text.
use re2::*;
let o: Options = CannedOptions::POSIX.into();
let r = RE2::compile("a(.+)d(f)".into(), o)?;
assert_eq!(2, r.num_captures());
let msg = "the asdf is withdfin me";
// The 0 case still works, but just calls .partial_match():
assert!(r.partial_match_capturing::<0>(msg).is_some());
let [s1, s2] = r.partial_match_capturing(msg).unwrap();
assert_eq!(s1, "sdf is with");
assert_eq!(s2, "f");
// The result isn't copied, it points to the same memory:
assert_eq!(s1.as_bytes().as_ptr(), msg[5..].as_bytes().as_ptr());
assert_eq!(s2.as_bytes().as_ptr(), msg[17..].as_bytes().as_ptr());Sourcepub fn consume(&self, text: &mut &str) -> bool
pub fn consume(&self, text: &mut &str) -> bool
If the pattern matches some prefix of text, advance text past the
match.
let r: re2::RE2 = "a.{2}".parse()?;
let mut s = "asdf";
assert!(r.consume(&mut s));
assert_eq!(s, "f");Sourcepub fn consume_capturing<'a, const N: usize>(
&self,
text: &mut &'a str,
) -> Option<[&'a str; N]>
pub fn consume_capturing<'a, const N: usize>( &self, text: &mut &'a str, ) -> Option<[&'a str; N]>
If the pattern matches some prefix of text, advance text past the
match and return some subset of captured sub-patterns.
let r: re2::RE2 = "a(.)d(f)".parse()?;
assert_eq!(2, r.num_captures());
let mut msg = "asdfasdfe";
// The 0 case still works, but just calls .consume():
assert!(r.consume_capturing::<0>(&mut msg).is_some());
assert_eq!(msg, "asdfe");
let [s1, s2] = r.consume_capturing(&mut msg).unwrap();
assert_eq!(s1, "s");
assert_eq!(s2, "f");
assert_eq!(msg, "e");Sourcepub fn find_and_consume(&self, text: &mut &str) -> bool
pub fn find_and_consume(&self, text: &mut &str) -> bool
If the pattern matches anywhere in text, advance text past the match.
Like Self::consume(), but does not anchor the match at the beginning
of the text.
let r: re2::RE2 = "a.{2}".parse()?;
let mut s = "the asdf";
assert!(r.find_and_consume(&mut s));
assert_eq!(s, "f");Sourcepub fn find_and_consume_capturing<'a, const N: usize>(
&self,
text: &mut &'a str,
) -> Option<[&'a str; N]>
pub fn find_and_consume_capturing<'a, const N: usize>( &self, text: &mut &'a str, ) -> Option<[&'a str; N]>
If the pattern matches anywhere in text, advance text past the match
and return some subset of captured sub-patterns.
Like Self::consume_capturing(), but does not anchor the match at the
beginning of the text.
let r: re2::RE2 = "a(.)d(f)".parse()?;
assert_eq!(2, r.num_captures());
let mut msg = "the asdf and the asdfe";
// The 0 case still works, but just calls .find_and_consume():
assert!(r.find_and_consume_capturing::<0>(&mut msg).is_some());
assert_eq!(msg, " and the asdfe");
let [s1, s2] = r.find_and_consume_capturing(&mut msg).unwrap();
assert_eq!(s1, "s");
assert_eq!(s2, "f");
assert_eq!(msg, "e");Sourcepub fn match_no_captures(
&self,
text: &str,
range: Range<usize>,
anchor: Anchor,
) -> bool
pub fn match_no_captures( &self, text: &str, range: Range<usize>, anchor: Anchor, ) -> bool
General matching routine. Suitable for calling from higher-level code.
Match against text within range, taking into account anchor. Returns
true if match found, false if not.
use re2::{RE2, options::Anchor};
let r: RE2 = "(foo)|(bar)baz".parse()?;
let msg = "barbazbla";
assert!(r.match_no_captures(msg, 0..msg.len(), Anchor::Unanchored));
assert!(r.match_no_captures(msg, 0..msg.len(), Anchor::AnchorStart));
assert!(!r.match_no_captures(msg, 0..msg.len(), Anchor::AnchorBoth));
assert!(r.match_no_captures(msg, 0..6, Anchor::AnchorBoth));
assert!(!r.match_no_captures(msg, 1..msg.len(), Anchor::Unanchored));Sourcepub fn match_routine<'a, const N: usize>(
&self,
text: &'a str,
range: Range<usize>,
anchor: Anchor,
) -> Option<[&'a str; N]>
pub fn match_routine<'a, const N: usize>( &self, text: &'a str, range: Range<usize>, anchor: Anchor, ) -> Option<[&'a str; N]>
General matching routine with capture groups. Suitable for calling from higher-level code.
Match against text within range, taking into account anchor. Returns
Some if match found, None if not.
NB: Unlike other matching methods, the 0th element of the result
corresponds to the entire matched text, so the indices of the returned
array correspond to the indices of declared capture groups e.g. from
Self::named_groups(). Also unlike other matching methods, requesting
more captures than the number of declared capture groups will simply
return empty strings for the excessive captures instead of failing the
match.
Performance-wise, N == 0 (capturing nothing, like
Self::match_no_captures()) is much faster than N == 1 (only
capturing the entire match text), which is faster than N > 1 (if any
capture groups are selected).
use re2::{RE2, options::Anchor};
let r: RE2 = "(foo)|(bar)baz".parse()?;
let msg = "barbazbla";
let [s0, s1, s2, s3] = r.match_routine(msg, 0..msg.len(), Anchor::AnchorStart).unwrap();
assert_eq!(s0, "barbaz");
assert_eq!(s1, "");
assert_eq!(s2, "bar");
assert_eq!(s3, "");Source§impl RE2
§String Replacement with a Rewrite String
These methods use a mutable StringWrapper instance with dynamically
allocated data to record the result of applying a “rewrite string” to the
capture groups for a given match using Self::vector_rewrite(). They may
mutate data from the string or append to the string upon a successful match.
impl RE2
§String Replacement with a Rewrite String
These methods use a mutable StringWrapper instance with dynamically
allocated data to record the result of applying a “rewrite string” to the
capture groups for a given match using Self::vector_rewrite(). They may
mutate data from the string or append to the string upon a successful match.
Within a rewrite string, backslash-escaped digits (\1 to \9) can be
used to insert text matching corresponding parenthesized group
from the pattern. \0 refers to the entire matched text:
use re2::{RE2, string::StringWrapper};
let r: RE2 = "b+".parse()?;
let mut s = StringWrapper::from_view("yabba dabba doo".into());
assert!(r.replace(&mut s, "d"));
assert_eq!("yada dabba doo", unsafe { s.as_view().as_str() });
assert!(r.replace(&mut s, r"!\0!"));
assert_eq!("yada da!bb!a doo", unsafe { s.as_view().as_str() });Sourcepub fn replace(&self, text: &mut StringWrapper, rewrite: &str) -> bool
pub fn replace(&self, text: &mut StringWrapper, rewrite: &str) -> bool
Replace the first match of this pattern in text with rewrite.
Returns true if the pattern matches and a replacement occurs,
false otherwise.
let r: re2::RE2 = ".he".parse()?;
let mut s = re2::string::StringWrapper::from_view("all the king's men".into());
assert!(r.replace(&mut s, "duh"));
assert_eq!(unsafe { s.as_view().as_str() }, "all duh king's men");Sourcepub fn replace_n(
&self,
text: &mut StringWrapper,
rewrite: &str,
limit: usize,
) -> usize
pub fn replace_n( &self, text: &mut StringWrapper, rewrite: &str, limit: usize, ) -> usize
Applies Self::replace() to text at most limit times. Returns the
number of replacements made.
let r: re2::RE2 = ".he".parse()?;
let mut s = re2::string::StringWrapper::from_view(
"all the king's horses and all the king's men".into());
assert_eq!(2, r.replace_n(&mut s, "duh", 3));
assert_eq!(
unsafe { s.as_view().as_str() },
"all duh king's horses and all duh king's men",
);Sourcepub fn global_replace(&self, text: &mut StringWrapper, rewrite: &str) -> usize
pub fn global_replace(&self, text: &mut StringWrapper, rewrite: &str) -> usize
Applies Self::replace() to text for all non-overlapping occurrences
of the pattern. Returns the number of replacements made.
let r: re2::RE2 = ".he".parse()?;
let mut s = re2::string::StringWrapper::from_view(
"all the king's horses and all the king's men".into());
assert_eq!(2, r.global_replace(&mut s, "duh"));
assert_eq!(
unsafe { s.as_view().as_str() },
"all duh king's horses and all duh king's men",
);Sourcepub fn extract(
&self,
text: &str,
rewrite: &str,
out: &mut StringWrapper,
) -> bool
pub fn extract( &self, text: &str, rewrite: &str, out: &mut StringWrapper, ) -> bool
Like Self::replace(), except that if the pattern matches, rewrite is
copied into out with substitutions. The non-matching portions of
text are ignored.
Returns true iff a match occured and the extraction happened
successfully; if no match occurs, the string is left unaffected.
REQUIRES: text must not alias any part of out!
let r: re2::RE2 = "(.h)e".parse()?;
let mut s = re2::string::StringWrapper::blank();
assert!(r.extract("all the king's men", r"\1a", &mut s));
assert_eq!(unsafe { s.as_view().as_str() }, "tha");Source§impl RE2
§Iterators
These methods make use of lower-level matching methods like
Self::match_routine() to produce lazy streams of results.
impl RE2
§Iterators
These methods make use of lower-level matching methods like
Self::match_routine() to produce lazy streams of results.
Sourcepub fn find_iter<'r, 'h: 'r, const N: usize>(
&'r self,
hay: &'h str,
) -> impl Iterator<Item = [&'h str; N]> + 'r
pub fn find_iter<'r, 'h: 'r, const N: usize>( &'r self, hay: &'h str, ) -> impl Iterator<Item = [&'h str; N]> + 'r
Yields all non-overlapping matches in hay. Supports capture groups.
The N argument is interpreted the same way as in
Self::match_routine(), where requesting fewer submatches is more
performant, and the 0th submatch corresponds to the entire matched text.
However, note that N must be at least 1 when calling this method in
order to record match boundaries to avoid overlaps.
NB: if no input is consumed upon searching the regex, iteration will end to avoid looping infinitely.
let r: re2::RE2 = "a+(.)".parse()?;
let hay = "aardvarks all ailing: awesome";
let whole_matches: Vec<&str> = r.find_iter::<1>(hay).map(|[m]| m).collect();
let submatches: Vec<&str> = r.find_iter::<2>(hay).map(|[_, m]| m).collect();
assert_eq!(&whole_matches, &["aar", "ar", "al", "ai", "aw"]);
assert_eq!(&submatches, &["r", "r", "l", "i", "w"]);Sourcepub fn split<'r, 'h: 'r>(
&'r self,
hay: &'h str,
) -> impl Iterator<Item = &'h str> + 'r
pub fn split<'r, 'h: 'r>( &'r self, hay: &'h str, ) -> impl Iterator<Item = &'h str> + 'r
Yields all slices between matches of the pattern.
Split by arbitrary amount of tabs or whitespace:
let r: re2::RE2 = r"[ \t]+".parse()?;
let hay = "a b \t c\td e";
let fields: Vec<&str> = r.split(hay).collect();
assert_eq!(&fields, &["a", "b", "c", "d", "e"]);Multiple contiguous matches yield empty slices:
let r: re2::RE2 = "X".parse()?;
let hay = "XXXXaXXbXc";
let chunks: Vec<&str> = r.split(hay).collect();
assert_eq!(&chunks, &["", "", "", "", "a", "", "b", "c"]);Separators at start or end also yield empty slices:
let r: re2::RE2 = "0".parse()?;
let hay = "010";
let chunks: Vec<&str> = r.split(hay).collect();
assert_eq!(&chunks, &["", "1", ""]);Source§impl RE2
§Introspection
Introspection methods to investigate match groups and rewrite strings.
impl RE2
§Introspection
Introspection methods to investigate match groups and rewrite strings.
Sourcepub fn max_submatch(rewrite: &str) -> usize
pub fn max_submatch(rewrite: &str) -> usize
Returns the maximum submatch needed for the rewrite to be done by
Self::replace(). E.g. if rewrite == r"foo \2,\1", returns 2.
Self::check_rewrite() ensures that this number is no larger than the
result of Self::num_captures().
use re2::RE2;
assert_eq!(0, RE2::max_submatch("asdf".into()));
assert_eq!(0, RE2::max_submatch(r"\0asdf".into()));
assert_eq!(1, RE2::max_submatch(r"\0a\1sdf".into()));
assert_eq!(3, RE2::max_submatch(r"\3a\1sdf".into()));Sourcepub fn num_captures(&self) -> usize
pub fn num_captures(&self) -> usize
Return the number of capture groups in the current pattern.
Alternately, this can be understood as the highest capture group index
which this pattern can support in a rewrite string, with 0 referring to
the entire match. Also see Self::max_submatch().
use re2::RE2;
assert_eq!(0, "a.df".parse::<RE2>()?.num_captures());
assert_eq!(1, "a(.)df".parse::<RE2>()?.num_captures());
assert_eq!(2, "a((.)df)".parse::<RE2>()?.num_captures());
assert_eq!(3, "(?P<foo>a)((.)df)".parse::<RE2>()?.num_captures());Sourcepub fn named_groups(&self) -> impl Iterator<Item = NamedGroup<'_>> + '_
pub fn named_groups(&self) -> impl Iterator<Item = NamedGroup<'_>> + '_
Return an FFI handle to a C++ iterator over the named capture groups.
This method does not provide information about positional-only capture
groups. Use Self::named_and_numbered_groups() for an iterator that
covers positional as well as named groups.
use re2::RE2;
assert_eq!(0, "a(.)df".parse::<RE2>()?.named_groups().count());
assert_eq!(1, "a(?P<hey>.)df".parse::<RE2>()?.named_groups().count());
// Not all captures are named:
let r: RE2 = "a(?P<y>(?P<x>.)d(f)(?P<z>e))".parse()?;
assert_eq!(4, r.num_captures());
// Results are sorted by number:
let groups: Vec<(&str, usize)> = r.named_groups()
.map(|g| (g.name(), *g.index()))
.collect();
assert_eq!(vec![("y", 1), ("x", 2), ("z", 4)], groups);Sourcepub fn named_and_numbered_groups(
&self,
) -> impl ExactSizeIterator<Item = Option<&str>>
pub fn named_and_numbered_groups( &self, ) -> impl ExactSizeIterator<Item = Option<&str>>
Return an iterator covering both named and positional-only groups.
Positional-only groups are represented with None instead of a
str.
The index of each group can be recovered by calling .enumerate() on the
result. This is possible because this iterator also generates a
positional-only group at index 0, which can be thought
of as corresponding to the 0th group in a rewrite string (aka the entire
match).
While most use cases will likely employ either only positional or only named groups, this method can be useful for introspection over uncontrolled inputs.
let r: re2::RE2 = "a(?P<y>(?P<x>.)d(f)(?P<z>e)(n))".parse()?;
assert_eq!(5, r.num_captures());
let indexed: Vec<(usize, Option<&str>)> = r.named_and_numbered_groups()
.enumerate()
.collect();
assert_eq!(
&indexed,
&[(0, None), (1, Some("y")), (2, Some("x")), (3, None), (4, Some("z")), (5, None)] );Sourcepub fn check_rewrite(&self, rewrite: &str) -> Result<(), RewriteError>
pub fn check_rewrite(&self, rewrite: &str) -> Result<(), RewriteError>
Check that the given rewrite string is suitable for use with this
regular expression.
It checks that:
- The regular expression has enough parenthesized subexpressions to
satisfy all of the
\Ntokens in rewrite - The rewrite string doesn’t have any syntax errors. E.g.,
\followed by anything other than a digit or\.
A true return value guarantees that Self::replace() and
Self::extract() won’t fail because of a bad rewrite string.
use re2::{RE2, error::RewriteError};
let r: RE2 = "asdf".parse()?;
r.check_rewrite("a").unwrap();
r.check_rewrite(r"a\0b").unwrap();
assert_eq!(
RewriteError {
message: "Rewrite schema requests 1 matches, but the regexp only has 0 parenthesized subexpressions.".to_string(),
},
r.check_rewrite(r"a\0b\1").err().unwrap(),
);Sourcepub fn vector_rewrite<const N: usize>(
&self,
out: &mut StringWrapper,
rewrite: &str,
inputs: [&str; N],
) -> bool
pub fn vector_rewrite<const N: usize>( &self, out: &mut StringWrapper, rewrite: &str, inputs: [&str; N], ) -> bool
Append the rewrite string, with backslash substitutions from inputs,
to string out.
Returns true on success. This method can fail because of a malformed
rewrite string. Self::check_rewrite() guarantees that the rewrite will
be sucessful.
let mut sw = re2::string::StringWrapper::blank();
let r: re2::RE2 = "a(s+)d(f+)".parse()?;
assert!(r.vector_rewrite(&mut sw, r"bb\1cc\0dd\2", ["asdff", "s", "ff"]));
assert_eq!(unsafe { sw.as_view().as_str() }, "bbsccasdffddff");Trait Implementations§
Source§impl Ord for RE2
impl Ord for RE2
Source§impl PartialOrd for RE2
impl PartialOrd for RE2
impl Eq for RE2
Auto Trait Implementations§
impl Freeze for RE2
impl RefUnwindSafe for RE2
impl Send for RE2
impl Sync for RE2
impl Unpin for RE2
impl UnwindSafe for RE2
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.