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
use std::borrow::Cow;
use super::{Regex, Captures};
/// Replacer describes types that can be used to replace matches in a string.
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>;
}
impl<'t> Replacer for &'t str {
fn reg_replace(&mut self, _: &Captures) -> Cow<str> {
(*self).into()
}
}
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
/// # extern crate onig; 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
/// # extern crate onig; 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
}
}