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