xref: /aosp_15_r20/external/abseil-cpp/absl/strings/str_replace_test.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "absl/strings/str_replace.h"
16 
17 #include <list>
18 #include <map>
19 #include <string>
20 #include <tuple>
21 #include <utility>
22 #include <vector>
23 
24 #include "gtest/gtest.h"
25 #include "absl/strings/str_cat.h"
26 #include "absl/strings/str_split.h"
27 #include "absl/strings/string_view.h"
28 
TEST(StrReplaceAll,OneReplacement)29 TEST(StrReplaceAll, OneReplacement) {
30   std::string s;
31 
32   // Empty string.
33   s = absl::StrReplaceAll(s, {{"", ""}});
34   EXPECT_EQ(s, "");
35   s = absl::StrReplaceAll(s, {{"x", ""}});
36   EXPECT_EQ(s, "");
37   s = absl::StrReplaceAll(s, {{"", "y"}});
38   EXPECT_EQ(s, "");
39   s = absl::StrReplaceAll(s, {{"x", "y"}});
40   EXPECT_EQ(s, "");
41 
42   // Empty substring.
43   s = absl::StrReplaceAll("abc", {{"", ""}});
44   EXPECT_EQ(s, "abc");
45   s = absl::StrReplaceAll("abc", {{"", "y"}});
46   EXPECT_EQ(s, "abc");
47   s = absl::StrReplaceAll("abc", {{"x", ""}});
48   EXPECT_EQ(s, "abc");
49 
50   // Substring not found.
51   s = absl::StrReplaceAll("abc", {{"xyz", "123"}});
52   EXPECT_EQ(s, "abc");
53 
54   // Replace entire string.
55   s = absl::StrReplaceAll("abc", {{"abc", "xyz"}});
56   EXPECT_EQ(s, "xyz");
57 
58   // Replace once at the start.
59   s = absl::StrReplaceAll("abc", {{"a", "x"}});
60   EXPECT_EQ(s, "xbc");
61 
62   // Replace once in the middle.
63   s = absl::StrReplaceAll("abc", {{"b", "x"}});
64   EXPECT_EQ(s, "axc");
65 
66   // Replace once at the end.
67   s = absl::StrReplaceAll("abc", {{"c", "x"}});
68   EXPECT_EQ(s, "abx");
69 
70   // Replace multiple times with varying lengths of original/replacement.
71   s = absl::StrReplaceAll("ababa", {{"a", "xxx"}});
72   EXPECT_EQ(s, "xxxbxxxbxxx");
73 
74   s = absl::StrReplaceAll("ababa", {{"b", "xxx"}});
75   EXPECT_EQ(s, "axxxaxxxa");
76 
77   s = absl::StrReplaceAll("aaabaaabaaa", {{"aaa", "x"}});
78   EXPECT_EQ(s, "xbxbx");
79 
80   s = absl::StrReplaceAll("abbbabbba", {{"bbb", "x"}});
81   EXPECT_EQ(s, "axaxa");
82 
83   // Overlapping matches are replaced greedily.
84   s = absl::StrReplaceAll("aaa", {{"aa", "x"}});
85   EXPECT_EQ(s, "xa");
86 
87   // The replacements are not recursive.
88   s = absl::StrReplaceAll("aaa", {{"aa", "a"}});
89   EXPECT_EQ(s, "aa");
90 }
91 
TEST(StrReplaceAll,ManyReplacements)92 TEST(StrReplaceAll, ManyReplacements) {
93   std::string s;
94 
95   // Empty string.
96   s = absl::StrReplaceAll("", {{"", ""}, {"x", ""}, {"", "y"}, {"x", "y"}});
97   EXPECT_EQ(s, "");
98 
99   // Empty substring.
100   s = absl::StrReplaceAll("abc", {{"", ""}, {"", "y"}, {"x", ""}});
101   EXPECT_EQ(s, "abc");
102 
103   // Replace entire string, one char at a time
104   s = absl::StrReplaceAll("abc", {{"a", "x"}, {"b", "y"}, {"c", "z"}});
105   EXPECT_EQ(s, "xyz");
106   s = absl::StrReplaceAll("zxy", {{"z", "x"}, {"x", "y"}, {"y", "z"}});
107   EXPECT_EQ(s, "xyz");
108 
109   // Replace once at the start (longer matches take precedence)
110   s = absl::StrReplaceAll("abc", {{"a", "x"}, {"ab", "xy"}, {"abc", "xyz"}});
111   EXPECT_EQ(s, "xyz");
112 
113   // Replace once in the middle.
114   s = absl::StrReplaceAll(
115       "Abc!", {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc", "yz"}, {"c", "z"}});
116   EXPECT_EQ(s, "Ayz!");
117 
118   // Replace once at the end.
119   s = absl::StrReplaceAll(
120       "Abc!",
121       {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc!", "yz?"}, {"c!", "z;"}});
122   EXPECT_EQ(s, "Ayz?");
123 
124   // Replace multiple times with varying lengths of original/replacement.
125   s = absl::StrReplaceAll("ababa", {{"a", "xxx"}, {"b", "XXXX"}});
126   EXPECT_EQ(s, "xxxXXXXxxxXXXXxxx");
127 
128   // Overlapping matches are replaced greedily.
129   s = absl::StrReplaceAll("aaa", {{"aa", "x"}, {"a", "X"}});
130   EXPECT_EQ(s, "xX");
131   s = absl::StrReplaceAll("aaa", {{"a", "X"}, {"aa", "x"}});
132   EXPECT_EQ(s, "xX");
133 
134   // Two well-known sentences
135   s = absl::StrReplaceAll("the quick brown fox jumped over the lazy dogs",
136                           {
137                               {"brown", "box"},
138                               {"dogs", "jugs"},
139                               {"fox", "with"},
140                               {"jumped", "five"},
141                               {"over", "dozen"},
142                               {"quick", "my"},
143                               {"the", "pack"},
144                               {"the lazy", "liquor"},
145                           });
146   EXPECT_EQ(s, "pack my box with five dozen liquor jugs");
147 }
148 
TEST(StrReplaceAll,ManyReplacementsInMap)149 TEST(StrReplaceAll, ManyReplacementsInMap) {
150   std::map<const char *, const char *> replacements;
151   replacements["$who"] = "Bob";
152   replacements["$count"] = "5";
153   replacements["#Noun"] = "Apples";
154   std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!",
155                                       replacements);
156   EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
157 }
158 
TEST(StrReplaceAll,ReplacementsInPlace)159 TEST(StrReplaceAll, ReplacementsInPlace) {
160   std::string s = std::string("$who bought $count #Noun. Thanks $who!");
161   int count;
162   count = absl::StrReplaceAll({{"$count", absl::StrCat(5)},
163                               {"$who", "Bob"},
164                               {"#Noun", "Apples"}}, &s);
165   EXPECT_EQ(count, 4);
166   EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
167 }
168 
TEST(StrReplaceAll,ReplacementsInPlaceInMap)169 TEST(StrReplaceAll, ReplacementsInPlaceInMap) {
170   std::string s = std::string("$who bought $count #Noun. Thanks $who!");
171   std::map<absl::string_view, absl::string_view> replacements;
172   replacements["$who"] = "Bob";
173   replacements["$count"] = "5";
174   replacements["#Noun"] = "Apples";
175   int count;
176   count = absl::StrReplaceAll(replacements, &s);
177   EXPECT_EQ(count, 4);
178   EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
179 }
180 
181 struct Cont {
182   Cont() = default;
ContCont183   explicit Cont(absl::string_view src) : data(src) {}
184 
185   absl::string_view data;
186 };
187 
188 template <int index>
get(const Cont & c)189 absl::string_view get(const Cont& c) {
190   auto splitter = absl::StrSplit(c.data, ':');
191   auto it = splitter.begin();
192   for (int i = 0; i < index; ++i) ++it;
193 
194   return *it;
195 }
196 
TEST(StrReplaceAll,VariableNumber)197 TEST(StrReplaceAll, VariableNumber) {
198   std::string s;
199   {
200     std::vector<std::pair<std::string, std::string>> replacements;
201 
202     s = "abc";
203     EXPECT_EQ(0, absl::StrReplaceAll(replacements, &s));
204     EXPECT_EQ("abc", s);
205 
206     s = "abc";
207     replacements.push_back({"a", "A"});
208     EXPECT_EQ(1, absl::StrReplaceAll(replacements, &s));
209     EXPECT_EQ("Abc", s);
210 
211     s = "abc";
212     replacements.push_back({"b", "B"});
213     EXPECT_EQ(2, absl::StrReplaceAll(replacements, &s));
214     EXPECT_EQ("ABc", s);
215 
216     s = "abc";
217     replacements.push_back({"d", "D"});
218     EXPECT_EQ(2, absl::StrReplaceAll(replacements, &s));
219     EXPECT_EQ("ABc", s);
220 
221     EXPECT_EQ("ABcABc", absl::StrReplaceAll("abcabc", replacements));
222   }
223 
224   {
225     std::map<const char*, const char*> replacements;
226     replacements["aa"] = "x";
227     replacements["a"] = "X";
228     s = "aaa";
229     EXPECT_EQ(2, absl::StrReplaceAll(replacements, &s));
230     EXPECT_EQ("xX", s);
231 
232     EXPECT_EQ("xxX", absl::StrReplaceAll("aaaaa", replacements));
233   }
234 
235   {
236     std::list<std::pair<absl::string_view, absl::string_view>> replacements = {
237         {"a", "x"}, {"b", "y"}, {"c", "z"}};
238 
239     std::string s = absl::StrReplaceAll("abc", replacements);
240     EXPECT_EQ(s, "xyz");
241   }
242 
243   {
244     using X = std::tuple<absl::string_view, std::string, int>;
245     std::vector<X> replacements(3);
246     replacements[0] = X{"a", "x", 1};
247     replacements[1] = X{"b", "y", 0};
248     replacements[2] = X{"c", "z", -1};
249 
250     std::string s = absl::StrReplaceAll("abc", replacements);
251     EXPECT_EQ(s, "xyz");
252   }
253 
254   {
255     std::vector<Cont> replacements(3);
256     replacements[0] = Cont{"a:x"};
257     replacements[1] = Cont{"b:y"};
258     replacements[2] = Cont{"c:z"};
259 
260     std::string s = absl::StrReplaceAll("abc", replacements);
261     EXPECT_EQ(s, "xyz");
262   }
263 }
264 
265 // Same as above, but using the in-place variant of absl::StrReplaceAll,
266 // that returns the # of replacements performed.
TEST(StrReplaceAll,Inplace)267 TEST(StrReplaceAll, Inplace) {
268   std::string s;
269   int reps;
270 
271   // Empty string.
272   s = "";
273   reps = absl::StrReplaceAll({{"", ""}, {"x", ""}, {"", "y"}, {"x", "y"}}, &s);
274   EXPECT_EQ(reps, 0);
275   EXPECT_EQ(s, "");
276 
277   // Empty substring.
278   s = "abc";
279   reps = absl::StrReplaceAll({{"", ""}, {"", "y"}, {"x", ""}}, &s);
280   EXPECT_EQ(reps, 0);
281   EXPECT_EQ(s, "abc");
282 
283   // Replace entire string, one char at a time
284   s = "abc";
285   reps = absl::StrReplaceAll({{"a", "x"}, {"b", "y"}, {"c", "z"}}, &s);
286   EXPECT_EQ(reps, 3);
287   EXPECT_EQ(s, "xyz");
288   s = "zxy";
289   reps = absl::StrReplaceAll({{"z", "x"}, {"x", "y"}, {"y", "z"}}, &s);
290   EXPECT_EQ(reps, 3);
291   EXPECT_EQ(s, "xyz");
292 
293   // Replace once at the start (longer matches take precedence)
294   s = "abc";
295   reps = absl::StrReplaceAll({{"a", "x"}, {"ab", "xy"}, {"abc", "xyz"}}, &s);
296   EXPECT_EQ(reps, 1);
297   EXPECT_EQ(s, "xyz");
298 
299   // Replace once in the middle.
300   s = "Abc!";
301   reps = absl::StrReplaceAll(
302       {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc", "yz"}, {"c", "z"}}, &s);
303   EXPECT_EQ(reps, 1);
304   EXPECT_EQ(s, "Ayz!");
305 
306   // Replace once at the end.
307   s = "Abc!";
308   reps = absl::StrReplaceAll(
309       {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc!", "yz?"}, {"c!", "z;"}}, &s);
310   EXPECT_EQ(reps, 1);
311   EXPECT_EQ(s, "Ayz?");
312 
313   // Replace multiple times with varying lengths of original/replacement.
314   s = "ababa";
315   reps = absl::StrReplaceAll({{"a", "xxx"}, {"b", "XXXX"}}, &s);
316   EXPECT_EQ(reps, 5);
317   EXPECT_EQ(s, "xxxXXXXxxxXXXXxxx");
318 
319   // Overlapping matches are replaced greedily.
320   s = "aaa";
321   reps = absl::StrReplaceAll({{"aa", "x"}, {"a", "X"}}, &s);
322   EXPECT_EQ(reps, 2);
323   EXPECT_EQ(s, "xX");
324   s = "aaa";
325   reps = absl::StrReplaceAll({{"a", "X"}, {"aa", "x"}}, &s);
326   EXPECT_EQ(reps, 2);
327   EXPECT_EQ(s, "xX");
328 
329   // Two well-known sentences
330   s = "the quick brown fox jumped over the lazy dogs";
331   reps = absl::StrReplaceAll(
332       {
333           {"brown", "box"},
334           {"dogs", "jugs"},
335           {"fox", "with"},
336           {"jumped", "five"},
337           {"over", "dozen"},
338           {"quick", "my"},
339           {"the", "pack"},
340           {"the lazy", "liquor"},
341       },
342       &s);
343   EXPECT_EQ(reps, 8);
344   EXPECT_EQ(s, "pack my box with five dozen liquor jugs");
345 }
346