delta_lib/utils/
regex_replacement.rs1use std::borrow::Cow;
2
3use regex::{Regex, RegexBuilder};
4
5#[derive(Clone, Debug)]
6pub struct RegexReplacement {
7 regex: Regex,
8 replacement: String,
9 replace_all: bool,
10}
11
12impl RegexReplacement {
13 pub fn from_sed_command(sed_command: &str) -> Option<Self> {
14 let sep = sed_command.chars().nth(1)?;
15 let mut parts = sed_command[2..].split(sep);
16 let regex = parts.next()?;
17 let replacement = parts.next()?.to_string();
18 let flags = parts.next()?;
19 let mut re_builder = RegexBuilder::new(regex);
20 let mut replace_all = false;
21 for flag in flags.chars() {
22 match flag {
23 'g' => {
24 replace_all = true;
25 }
26 'i' => {
27 re_builder.case_insensitive(true);
28 }
29 'm' => {
30 re_builder.multi_line(true);
31 }
32 's' => {
33 re_builder.dot_matches_new_line(true);
34 }
35 'U' => {
36 re_builder.swap_greed(true);
37 }
38 'x' => {
39 re_builder.ignore_whitespace(true);
40 }
41 _ => {}
42 }
43 }
44 let regex = re_builder.build().ok()?;
45 Some(RegexReplacement {
46 regex,
47 replacement,
48 replace_all,
49 })
50 }
51
52 pub fn execute<'t>(&self, s: &'t str) -> Cow<'t, str> {
53 if self.replace_all {
54 self.regex.replace_all(s, &self.replacement)
55 } else {
56 self.regex.replace(s, &self.replacement)
57 }
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn test_sed_command() {
67 let command = "s,foo,bar,";
68 let rr = RegexReplacement::from_sed_command(command).unwrap();
69 assert_eq!(rr.regex.as_str(), "foo");
70 assert_eq!(rr.replacement, "bar");
71 assert_eq!(rr.replace_all, false);
72 assert_eq!(rr.execute("foo"), "bar");
73 }
74
75 #[test]
76 fn test_sed_command_i_flag() {
77 let command = "s,FOO,bar,";
78 let rr = RegexReplacement::from_sed_command(command).unwrap();
79 assert_eq!(rr.execute("foo"), "foo");
80 let command = "s,FOO,bar,i";
81 let rr = RegexReplacement::from_sed_command(command).unwrap();
82 assert_eq!(rr.execute("foo"), "bar");
83 }
84
85 #[test]
86 fn test_sed_command_g_flag() {
87 let command = "s,foo,bar,";
88 let rr = RegexReplacement::from_sed_command(command).unwrap();
89 assert_eq!(rr.execute("foofoo"), "barfoo");
90 let command = "s,foo,bar,g";
91 let rr = RegexReplacement::from_sed_command(command).unwrap();
92 assert_eq!(rr.execute("foofoo"), "barbar");
93 }
94
95 #[test]
96 fn test_sed_command_with_named_captures() {
97 let command = r"s/(?P<last>[^,\s]+),\s+(?P<first>\S+)/$first $last/";
98 let rr = RegexReplacement::from_sed_command(command).unwrap();
99 assert_eq!(rr.execute("Springsteen, Bruce"), "Bruce Springsteen");
100 }
101
102 #[test]
103 fn test_sed_command_invalid() {
104 assert!(RegexReplacement::from_sed_command("").is_none());
105 assert!(RegexReplacement::from_sed_command("s").is_none());
106 assert!(RegexReplacement::from_sed_command("s,").is_none());
107 assert!(RegexReplacement::from_sed_command("s,,").is_none());
108 assert!(RegexReplacement::from_sed_command("s,,i").is_none());
109 assert!(RegexReplacement::from_sed_command("s,,,").is_some());
110 assert!(RegexReplacement::from_sed_command("s,,,i").is_some());
111 }
112}