#[cfg(doctest)]
doc_comment::doctest!("../README.md");
use regex::Regex;
pub trait StringReplaceAll {
fn replace_all<'a, P: Into<Pattern<'a>>>(&self, pattern: P, replacement: &str) -> String;
}
impl StringReplaceAll for String {
fn replace_all<'a, P: Into<Pattern<'a>>>(&self, pattern: P, replacement: &str) -> String {
match pattern.into() {
Pattern::Str(s) => self.replace(s, replacement),
Pattern::Regex(r) => r.replace_all(self, replacement).to_string(),
}
}
}
impl StringReplaceAll for str {
fn replace_all<'a, P: Into<Pattern<'a>>>(&self, pattern: P, replacement: &str) -> String {
self.to_string().replace_all(pattern, replacement)
}
}
pub fn string_replace_all<'a, P: Into<Pattern<'a>>>(
input: &str,
pattern: P,
replacement: &str,
) -> String {
let mut result = match pattern.into() {
Pattern::Str(s) => {
if s == replacement || s.is_empty() {
return input.to_string();
}
input.replace(s, replacement)
}
Pattern::Regex(r) => r.replace_all(input, replacement).to_string(),
};
if !replacement.is_empty() {
let cleanup_pattern = Regex::new(&format!("(?:{})+", regex::escape(replacement))).unwrap();
result = cleanup_pattern
.replace_all(&result, replacement)
.to_string();
}
result
}
pub enum Pattern<'a> {
Str(&'a str),
Regex(Regex),
}
impl<'a> From<&'a str> for Pattern<'a> {
fn from(s: &'a str) -> Self {
Pattern::Str(s)
}
}
impl<'a> From<&'a Regex> for Pattern<'a> {
fn from(r: &'a Regex) -> Self {
Pattern::Regex(r.clone())
}
}
#[cfg(test)]
mod tests {
use super::string_replace_all;
#[test]
fn test_basic_replacement() {
let input = "Hello world! Hello Rust!";
let result = string_replace_all(input, "Hello", "Hi");
assert_eq!(result, "Hi world! Hi Rust!");
}
#[test]
fn test_no_occurrences() {
let input = "Hello world!";
let result = string_replace_all(input, "Goodbye", "Hi");
assert_eq!(result, "Hello world!"); }
#[test]
fn test_replace_multiple_spaces() {
let input = "Hello world! This is Rust.";
let result = string_replace_all(input, " ", " "); assert_eq!(result, "Hello world! This is Rust.");
}
#[test]
fn test_replace_multiple_spaces_doubled() {
let input = "Hello world! This is Rust.";
let result = string_replace_all(input, " ", " "); assert_eq!(result, "Hello world! This is Rust.");
}
#[test]
fn test_replace_entire_string() {
let input = "Hello";
let result = string_replace_all(input, "Hello", "Hi");
assert_eq!(result, "Hi");
}
#[test]
fn test_replace_with_empty_string() {
let input = "Hello world!";
let result = string_replace_all(input, "world!", "");
assert_eq!(result, "Hello ");
}
#[test]
fn test_replace_empty_string() {
let input = "Hello world!";
let result = string_replace_all(input, "", "X");
assert_eq!(result, "Hello world!"); }
#[test]
fn test_multi_line() {
let input = r#"Hello (line 1)
world! (line 2)"#;
let result = {
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)", "");
string_replace_all(&result, " ", " ") };
assert_eq!(result, "Hello world!");
}
#[test]
fn test_replace_with_special_characters() {
let input = "Regex test with $pecial characters!";
let result = string_replace_all(input, "$pecial", "special");
assert_eq!(result, "Regex test with special characters!");
}
#[test]
fn test_replace_newlines() {
let input = "Line1\nLine2\nLine3";
let result = string_replace_all(input, "\n", " | ");
assert_eq!(result, "Line1 | Line2 | Line3");
}
#[test]
fn test_replace_unicode() {
let input = "Привет мир! こんにちは世界!";
let result = string_replace_all(input, "мир", "Rust");
assert_eq!(result, "Привет Rust! こんにちは世界!");
}
#[test]
fn test_regex_replacement() {
let text = "I think Ruth's dog is cuter than your dog!";
let regex = regex::Regex::new("(?i)Dog").unwrap();
let result = string_replace_all(text, ®ex, "ferret");
assert_eq!(result, "I think Ruth's ferret is cuter than your ferret!");
}
}
#[cfg(test)]
mod trait_tests {
use super::StringReplaceAll;
use regex::Regex;
#[test]
fn test_string_replace_all() {
let input = "Hello world!".to_string();
let result = input.replace_all("world", "Rust");
assert_eq!(result, "Hello Rust!");
}
#[test]
fn test_str_replace_all() {
let input = "Hello world!";
let result = input.replace_all("world", "Rust");
assert_eq!(result, "Hello Rust!");
}
#[test]
fn test_regex_replace_all() {
let input = "I love RustLang and rust programming!".to_string();
let regex = Regex::new("(?i)rust").unwrap();
let result = input.replace_all(®ex, "Go");
assert_eq!(result, "I love GoLang and Go programming!");
}
#[test]
fn test_replace_special_characters() {
let input = "Replace * special ** characters!".to_string();
let result = input.replace_all("*", "-");
assert_eq!(result, "Replace - special -- characters!");
}
#[test]
fn test_replace_entire_string() {
let input = "Completely replace this".to_string();
let result = input.replace_all("Completely replace this", "Done");
assert_eq!(result, "Done");
}
}