1use onig::{Captures, Regex, Replacer};
2use std::borrow::Cow;
3
4struct Dollarified<'a>(&'a str);
6
7fn capture_str<'t>(caps: &'t Captures, cap_ref: &str) -> Option<&'t str> {
13 cap_ref.parse::<usize>().ok().and_then(|p| caps.at(p))
14}
15
16impl<'a> Replacer for Dollarified<'a> {
17 fn reg_replace(&mut self, caps: &Captures) -> Cow<'_, str> {
18 let mut replacement = String::new();
19 let mut pattern = self.0;
20 while !pattern.is_empty() {
21 if let Some(position) = pattern.find('$') {
22 replacement.push_str(&pattern[..position]);
24 pattern = &pattern[position + 1..];
25
26 let ref_end = pattern
28 .find(|c| !char::is_numeric(c))
29 .unwrap_or(pattern.len());
30
31 if let Some(cap) = capture_str(caps, &pattern[..ref_end]) {
33 replacement.push_str(cap);
34 pattern = &pattern[ref_end..];
35 } else {
36 replacement.push('$');
37 }
38 } else {
39 replacement.push_str(pattern);
41 break;
42 }
43 }
44 replacement.into()
45 }
46}
47
48fn test_with(replacement: &str) {
49 let re = Regex::new(r"(\w+) (\w+)").unwrap();
50 let hay = "well (hello world) to you!";
51 println!(
52 "/{}/{}/ -> {}",
53 &hay,
54 &replacement,
55 re.replace(hay, Dollarified(replacement))
56 );
57}
58
59fn main() {
60 test_with("$2 $1");
61 test_with("($2 $1)");
62 test_with("|$2|$1|");
63 test_with("|$0|$2$1");
64 test_with("$$$");
65 test_with("$$$3");
66 test_with("$$2$3");
67 test_with("Literal replacement");
68}