string_replace_all/
lib.rs1#[cfg(doctest)]
2doc_comment::doctest!("../README.md");
3
4use regex::Regex;
5
6pub fn string_replace_all<'a, P: Into<Pattern<'a>>>(
58 input: &str,
59 pattern: P,
60 replacement: &str,
61) -> String {
62 let mut result = match pattern.into() {
63 Pattern::Str(s) => {
64 if s == replacement || s.is_empty() {
65 return input.to_string();
66 }
67 input.replace(s, replacement)
68 }
69 Pattern::Regex(r) => r.replace_all(input, replacement).to_string(),
70 };
71
72 if !replacement.is_empty() {
73 let cleanup_pattern = Regex::new(&format!("(?:{})+", regex::escape(replacement))).unwrap();
74 result = cleanup_pattern
75 .replace_all(&result, replacement)
76 .to_string();
77 }
78
79 result
80}
81
82pub enum Pattern<'a> {
84 Str(&'a str),
85 Regex(Regex),
86}
87
88impl<'a> From<&'a str> for Pattern<'a> {
89 fn from(s: &'a str) -> Self {
90 Pattern::Str(s)
91 }
92}
93
94impl<'a> From<&'a Regex> for Pattern<'a> {
95 fn from(r: &'a Regex) -> Self {
96 Pattern::Regex(r.clone())
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::string_replace_all;
103
104 #[test]
105 fn test_basic_replacement() {
106 let input = "Hello world! Hello Rust!";
107 let result = string_replace_all(input, "Hello", "Hi");
108 assert_eq!(result, "Hi world! Hi Rust!");
109 }
110
111 #[test]
112 fn test_no_occurrences() {
113 let input = "Hello world!";
114 let result = string_replace_all(input, "Goodbye", "Hi");
115 assert_eq!(result, "Hello world!"); }
117
118 #[test]
119 fn test_replace_multiple_spaces() {
120 let input = "Hello world! This is Rust.";
121 let result = string_replace_all(input, " ", " "); assert_eq!(result, "Hello world! This is Rust.");
123 }
124
125 #[test]
126 fn test_replace_multiple_spaces_doubled() {
127 let input = "Hello world! This is Rust.";
128 let result = string_replace_all(input, " ", " "); assert_eq!(result, "Hello world! This is Rust.");
130 }
131
132 #[test]
133 fn test_replace_entire_string() {
134 let input = "Hello";
135 let result = string_replace_all(input, "Hello", "Hi");
136 assert_eq!(result, "Hi");
137 }
138
139 #[test]
140 fn test_replace_with_empty_string() {
141 let input = "Hello world!";
142 let result = string_replace_all(input, "world!", "");
143 assert_eq!(result, "Hello ");
144 }
145
146 #[test]
147 fn test_replace_empty_string() {
148 let input = "Hello world!";
149 let result = string_replace_all(input, "", "X");
150 assert_eq!(result, "Hello world!"); }
152
153 #[test]
154 fn test_multi_line() {
155 let input = r#"Hello (line 1)
156 world! (line 2)"#;
157
158 let result = {
159 let result = string_replace_all(input, "\n", ""); let result = string_replace_all(&result, "\r", ""); let result = string_replace_all(&result, " (line 1)", ""); let result = string_replace_all(&result, " (line 2)", "");
163 string_replace_all(&result, " ", " ") };
165
166 assert_eq!(result, "Hello world!");
167 }
168
169 #[test]
170 fn test_replace_with_special_characters() {
171 let input = "Regex test with $pecial characters!";
172 let result = string_replace_all(input, "$pecial", "special");
173 assert_eq!(result, "Regex test with special characters!");
174 }
175
176 #[test]
177 fn test_replace_newlines() {
178 let input = "Line1\nLine2\nLine3";
179 let result = string_replace_all(input, "\n", " | ");
180 assert_eq!(result, "Line1 | Line2 | Line3");
181 }
182
183 #[test]
184 fn test_replace_unicode() {
185 let input = "Привет мир! こんにちは世界!";
186 let result = string_replace_all(input, "мир", "Rust");
187 assert_eq!(result, "Привет Rust! こんにちは世界!");
188 }
189
190 #[test]
191 fn test_regex_replacement() {
192 let text = "I think Ruth's dog is cuter than your dog!";
193 let regex = regex::Regex::new("(?i)Dog").unwrap(); let result = string_replace_all(text, ®ex, "ferret");
196 assert_eq!(result, "I think Ruth's ferret is cuter than your ferret!");
197 }
198}