1 extern crate onig;
2
3 use onig::{Captures, Regex, Replacer};
4 use std::borrow::Cow;
5
6 /// A string, with `$1` refering to the first capture group.
7 struct Dollarified<'a>(&'a str);
8
9 /// Capture Reference to Captured String
10 ///
11 /// Tries to convert a refernece to a capture to the captured text. If
12 /// the reference isn't a valid numeric capture group then no text is
13 /// returned.
capture_str<'t>(caps: &'t Captures, cap_ref: &str) -> Option<&'t str>14 fn capture_str<'t>(caps: &'t Captures, cap_ref: &str) -> Option<&'t str> {
15 cap_ref.parse::<usize>().ok().and_then(|p| caps.at(p))
16 }
17
18 impl<'a> Replacer for Dollarified<'a> {
reg_replace(&mut self, caps: &Captures) -> Cow<str>19 fn reg_replace(&mut self, caps: &Captures) -> Cow<str> {
20 let mut replacement = String::new();
21 let mut pattern = self.0;
22 while !pattern.is_empty() {
23 if let Some(position) = pattern.find('$') {
24 // push up to the replacement
25 replacement.push_str(&pattern[..position]);
26 pattern = &pattern[position + 1..];
27
28 // find the end of the capture reference
29 let ref_end = pattern
30 .find(|c| !char::is_numeric(c))
31 .unwrap_or(pattern.len());
32
33 // push the capture from this capture reference
34 if let Some(cap) = capture_str(caps, &pattern[..ref_end]) {
35 replacement.push_str(cap);
36 pattern = &pattern[ref_end..];
37 } else {
38 replacement.push('$');
39 }
40 } else {
41 // no replacements left
42 replacement.push_str(pattern);
43 break;
44 }
45 }
46 replacement.into()
47 }
48 }
49
test_with(replacement: &str)50 fn test_with(replacement: &str) {
51 let re = Regex::new(r"(\w+) (\w+)").unwrap();
52 let hay = "well (hello world) to you!";
53 println!(
54 "/{}/{}/ -> {}",
55 &hay,
56 &replacement,
57 re.replace(hay, Dollarified(replacement))
58 );
59 }
60
main()61 fn main() {
62 test_with("$2 $1");
63 test_with("($2 $1)");
64 test_with("|$2|$1|");
65 test_with("|$0|$2$1");
66 test_with("$$$");
67 test_with("$$$3");
68 test_with("$$2$3");
69 test_with("Literal replacement");
70 }
71