onig/replace.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
use super::{Captures, Regex};
use std::borrow::Cow;
/// Replacer describes types that can be used to replace matches in a string.
///
/// Implementations are provided for replacement using string literals
/// and `FnMut` callbacks. If this isn't enough for your replacement
/// needs a user-supplied `Replacer` implemenation can be
/// provided. For an example of a custom replacer implementation check
/// out `examples/dollar.rs` in the Onig crate.
pub trait Replacer {
/// Returns a possibly owned string that is used to replace the match
/// corresponding to the `caps` capture group.
fn reg_replace(&mut self, caps: &Captures) -> Cow<str>;
}
/// Replacement using Literal Strings
impl<'t> Replacer for &'t str {
fn reg_replace(&mut self, _: &Captures) -> Cow<str> {
(*self).into()
}
}
/// Replacement using `FnMut` Callbacks
impl<F> Replacer for F
where
F: FnMut(&Captures) -> String,
{
fn reg_replace<'a>(&'a mut self, caps: &Captures) -> Cow<'a, str> {
(*self)(caps).into()
}
}
impl Regex {
/// Replaces the leftmost-first match with the replacement provided.
/// The replacement can be a regular string or a function that takes
/// the matches `Captures` and returns the replaced string.
///
/// If no match is found, then a copy of the string is returned unchanged.
///
/// # Examples
///
/// Note that this function is polymorphic with respect to the replacement.
/// In typical usage, this can just be a normal string:
///
/// ```rust
/// # use onig::Regex;
/// # fn main() {
/// let re = Regex::new("[^01]+").unwrap();
/// assert_eq!(re.replace("1078910", ""), "1010");
/// # }
/// ```
///
/// But anything satisfying the `Replacer` trait will work. For example,
/// a closure of type `|&Captures| -> String` provides direct access to the
/// captures corresponding to a match. This allows one to access
/// submatches easily:
///
/// ```rust
/// # use onig::Regex;
/// # use onig::Captures; fn main() {
/// let re = Regex::new(r"([^,\s]+),\s+(\S+)").unwrap();
/// let result = re.replace("Springsteen, Bruce", |caps: &Captures| {
/// format!("{} {}", caps.at(2).unwrap_or(""), caps.at(1).unwrap_or(""))
/// });
/// assert_eq!(result, "Bruce Springsteen");
/// # }
/// ```
pub fn replace<R: Replacer>(&self, text: &str, rep: R) -> String {
self.replacen(text, 1, rep)
}
/// Replaces all non-overlapping matches in `text` with the
/// replacement provided. This is the same as calling `replacen` with
/// `limit` set to `0`.
///
/// See the documentation for `replace` for details on how to access
/// submatches in the replacement string.
pub fn replace_all<R: Replacer>(&self, text: &str, rep: R) -> String {
self.replacen(text, 0, rep)
}
/// Replaces at most `limit` non-overlapping matches in `text` with the
/// replacement provided. If `limit` is 0, then all non-overlapping matches
/// are replaced.
///
/// See the documentation for `replace` for details on how to access
/// submatches in the replacement string.
pub fn replacen<R: Replacer>(&self, text: &str, limit: usize, mut rep: R) -> String {
let mut new = String::with_capacity(text.len());
let mut last_match = 0;
for (i, cap) in self.captures_iter(text).enumerate() {
if limit > 0 && i >= limit {
break;
}
// unwrap on 0 is OK because captures only reports matches
let (s, e) = cap.pos(0).unwrap();
new.push_str(&text[last_match..s]);
new.push_str(&rep.reg_replace(&cap));
last_match = e;
}
new.push_str(&text[last_match..]);
new
}
}