1use std::collections::BTreeMap;
2
3pub fn multi_replace(s: &str, pats: &[(&str, &str)]) -> String {
29 let mut indices = BTreeMap::new();
30
31 for (pat, new) in pats {
32 for (i, p) in s.match_indices(pat) {
33 if indices
34 .range(..=i)
35 .next_back()
36 .map(|(pos, (len, _))| pos + len <= i)
37 .unwrap_or(true)
38 {
39 indices.insert(i, (p.len(), *new));
40 }
41 }
42 }
43
44 let mut result = String::new();
45 let mut end = 0usize;
46
47 for (pos, (len, new)) in indices {
48 result.push_str(unsafe { s.get_unchecked(end..pos) });
53 result.push_str(new);
54 end = pos + len;
55 }
56
57 if end < s.len() {
58 result.push_str(unsafe { s.get_unchecked(end..) });
61 }
62
63 result
64}
65
66pub fn exchange(s: &str, a: &str, b: &str) -> String {
72 let pat = if a.len() > b.len() {
75 [(a, b), (b, a)]
76 } else {
77 [(b, a), (a, b)]
78 };
79 multi_replace(s, &pat)
80}
81
82#[cfg(test)]
83mod test {
84 use super::*;
85
86 #[test]
87 fn replace() {
88 let s = "Hana is cute";
89
90 let r = multi_replace(s, &[("Hana", "Minami"), ("cute", "kawaii")]);
91 assert_eq!(r, "Minami is kawaii");
92 }
93
94 #[test]
95 fn not_match() {
96 assert_eq!(
97 "Hana is kawaii",
98 multi_replace("Hana is cute", &[("Rica", "Minami"), ("cute", "kawaii")])
99 )
100 }
101
102 #[test]
103 fn remain() {
104 assert_eq!(
105 "Hana is kawaii",
106 multi_replace("Minami is kawaii", &[("Minami", "Hana")])
107 )
108 }
109
110 #[test]
111 fn overlap() {
112 assert_eq!(
113 "Both Minami and Hana are kawaii",
114 multi_replace(
115 "Bouh Aoi and Hana are kawaii",
116 &[("Bouh", "Both"), ("Aoi", "Minami"), ("oi", "io")]
117 )
118 )
119 }
120
121 #[test]
122 fn exchange() {
123 let s = "Both Hana and Minami are kawaii";
124
125 assert_eq!(
126 "Both Minami and Hana are kawaii",
127 super::exchange(s, "Minami", "Hana")
128 );
129 assert_eq!(
130 "Both Minami and Hana are kawaii",
131 super::exchange(s, "Hana", "Minami")
132 );
133 assert_eq!(
134 "Both Hinata and Hina are kawaii",
135 super::exchange("Both Hina and Hinata are kawaii", "Hina", "Hinata")
136 );
137 assert_eq!(
138 "Both Hinata and Hina are kawaii",
139 super::exchange("Both Hina and Hinata are kawaii", "Hinata", "Hina")
140 );
141 }
142}