1 // Copyright (C) 2011 The Libphonenumber 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 // http://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 // Author: Philippe Liard
16
17 #include <algorithm>
18 #include <cassert>
19 #include <cstring>
20 #include <sstream>
21
22 #include "phonenumbers/stringutil.h"
23
24 namespace i18n {
25 namespace phonenumbers {
26
27 using std::equal;
28 using std::stringstream;
29
operator +(const string & s,int n)30 string operator+(const string& s, int n) { // NOLINT(runtime/string)
31 stringstream stream;
32
33 stream << s << n;
34 string result;
35 stream >> result;
36
37 return result;
38 }
39
40 template <typename T>
GenericSimpleItoa(const T & n)41 string GenericSimpleItoa(const T& n) {
42 stringstream stream;
43
44 stream << n;
45 string result;
46 stream >> result;
47
48 return result;
49 }
50
SimpleItoa(int n)51 string SimpleItoa(int n) {
52 return GenericSimpleItoa(n);
53 }
54
SimpleItoa(uint64 n)55 string SimpleItoa(uint64 n) {
56 return GenericSimpleItoa(n);
57 }
58
SimpleItoa(int64 n)59 string SimpleItoa(int64 n) {
60 return GenericSimpleItoa(n);
61 }
62
HasPrefixString(const string & s,const string & prefix)63 bool HasPrefixString(const string& s, const string& prefix) {
64 return s.size() >= prefix.size() &&
65 equal(s.begin(), s.begin() + prefix.size(), prefix.begin());
66 }
67
FindNth(const string & s,char c,int n)68 size_t FindNth(const string& s, char c, int n) {
69 size_t pos = string::npos;
70
71 for (int i = 0; i < n; ++i) {
72 pos = s.find_first_of(c, pos + 1);
73 if (pos == string::npos) {
74 break;
75 }
76 }
77 return pos;
78 }
79
SplitStringUsing(const string & s,const string & delimiter,vector<string> * result)80 void SplitStringUsing(const string& s, const string& delimiter,
81 vector<string>* result) {
82 assert(result);
83 size_t start_pos = 0;
84 size_t find_pos = string::npos;
85 if (delimiter.empty()) {
86 return;
87 }
88 while ((find_pos = s.find(delimiter, start_pos)) != string::npos) {
89 const string substring = s.substr(start_pos, find_pos - start_pos);
90 if (!substring.empty()) {
91 result->push_back(substring);
92 }
93 start_pos = find_pos + delimiter.length();
94 }
95 if (start_pos != s.length()) {
96 result->push_back(s.substr(start_pos));
97 }
98 }
99
StripString(string * s,const char * remove,char replacewith)100 void StripString(string* s, const char* remove, char replacewith) {
101 const char* str_start = s->c_str();
102 const char* str = str_start;
103 for (str = strpbrk(str, remove);
104 str != NULL;
105 str = strpbrk(str + 1, remove)) {
106 (*s)[str - str_start] = replacewith;
107 }
108 }
109
TryStripPrefixString(const string & in,const string & prefix,string * out)110 bool TryStripPrefixString(const string& in, const string& prefix, string* out) {
111 assert(out);
112 const bool has_prefix = in.compare(0, prefix.length(), prefix) == 0;
113 out->assign(has_prefix ? in.substr(prefix.length()) : in);
114
115 return has_prefix;
116 }
117
HasSuffixString(const string & s,const string & suffix)118 bool HasSuffixString(const string& s, const string& suffix) {
119 if (s.length() < suffix.length()) {
120 return false;
121 }
122 return s.compare(s.length() - suffix.length(), suffix.length(), suffix) == 0;
123 }
124
125 template <typename T>
GenericAtoi(const string & s,T * out)126 void GenericAtoi(const string& s, T* out) {
127 stringstream stream;
128 stream << s;
129 stream >> *out;
130 }
131
safe_strto32(const string & s,int32 * n)132 void safe_strto32(const string& s, int32 *n) {
133 GenericAtoi(s, n);
134 }
135
safe_strtou64(const string & s,uint64 * n)136 void safe_strtou64(const string& s, uint64 *n) {
137 GenericAtoi(s, n);
138 }
139
safe_strto64(const string & s,int64 * n)140 void safe_strto64(const string& s, int64* n) {
141 GenericAtoi(s, n);
142 }
143
strrmm(string * s,const string & chars)144 void strrmm(string* s, const string& chars) {
145 for (string::iterator it = s->begin(); it != s->end(); ) {
146 const char current_char = *it;
147 if (chars.find(current_char) != string::npos) {
148 it = s->erase(it);
149 } else {
150 ++it;
151 }
152 }
153 }
154
GlobalReplaceSubstring(const string & substring,const string & replacement,string * s)155 int GlobalReplaceSubstring(const string& substring,
156 const string& replacement,
157 string* s) {
158 assert(s != NULL);
159 if (s->empty() || substring.empty())
160 return 0;
161 string tmp;
162 int num_replacements = 0;
163 int pos = 0;
164 for (size_t match_pos = s->find(substring.data(), pos, substring.length());
165 match_pos != string::npos;
166 pos = match_pos + substring.length(),
167 match_pos = s->find(substring.data(), pos, substring.length())) {
168 ++num_replacements;
169 // Append the original content before the match.
170 tmp.append(*s, pos, match_pos - pos);
171 // Append the replacement for the match.
172 tmp.append(replacement.begin(), replacement.end());
173 }
174 // Append the content after the last match.
175 tmp.append(*s, pos, s->length() - pos);
176 s->swap(tmp);
177 return num_replacements;
178 }
179
180 // StringHolder class
181
StringHolder(const string & s)182 StringHolder::StringHolder(const string& s)
183 : string_(&s),
184 cstring_(NULL),
185 len_(s.size())
186 {}
187
StringHolder(const char * s)188 StringHolder::StringHolder(const char* s)
189 : string_(NULL),
190 cstring_(s),
191 len_(std::strlen(s))
192 {}
193
StringHolder(uint64 n)194 StringHolder::StringHolder(uint64 n)
195 : converted_string_(SimpleItoa(n)),
196 string_(&converted_string_),
197 cstring_(NULL),
198 len_(converted_string_.length())
199 {}
200
~StringHolder()201 StringHolder::~StringHolder() {}
202
203 // StrCat
204
205 // Implements s += sh; (s: string, sh: StringHolder)
operator +=(string & lhs,const StringHolder & rhs)206 string& operator+=(string& lhs, const StringHolder& rhs) {
207 const string* const s = rhs.GetString();
208 if (s) {
209 lhs += *s;
210 } else {
211 const char* const cs = rhs.GetCString();
212 if (cs)
213 lhs.append(cs, rhs.Length());
214 }
215 return lhs;
216 }
217
StrCat(const StringHolder & s1,const StringHolder & s2)218 string StrCat(const StringHolder& s1, const StringHolder& s2) {
219 string result;
220 result.reserve(s1.Length() + s2.Length() + 1);
221
222 result += s1;
223 result += s2;
224
225 return result;
226 }
227
StrCat(const StringHolder & s1,const StringHolder & s2,const StringHolder & s3)228 string StrCat(const StringHolder& s1, const StringHolder& s2,
229 const StringHolder& s3) {
230 string result;
231 result.reserve(s1.Length() + s2.Length() + s3.Length() + 1);
232
233 result += s1;
234 result += s2;
235 result += s3;
236
237 return result;
238 }
239
StrCat(const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4)240 string StrCat(const StringHolder& s1, const StringHolder& s2,
241 const StringHolder& s3, const StringHolder& s4) {
242 string result;
243 result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() + 1);
244
245 result += s1;
246 result += s2;
247 result += s3;
248 result += s4;
249
250 return result;
251 }
252
StrCat(const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4,const StringHolder & s5)253 string StrCat(const StringHolder& s1, const StringHolder& s2,
254 const StringHolder& s3, const StringHolder& s4,
255 const StringHolder& s5) {
256 string result;
257 result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() +
258 s5.Length() + 1);
259 result += s1;
260 result += s2;
261 result += s3;
262 result += s4;
263 result += s5;
264
265 return result;
266 }
267
StrCat(const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4,const StringHolder & s5,const StringHolder & s6)268 string StrCat(const StringHolder& s1, const StringHolder& s2,
269 const StringHolder& s3, const StringHolder& s4,
270 const StringHolder& s5, const StringHolder& s6) {
271 string result;
272 result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() +
273 s5.Length() + s6.Length() + 1);
274 result += s1;
275 result += s2;
276 result += s3;
277 result += s4;
278 result += s5;
279 result += s6;
280
281 return result;
282 }
283
StrCat(const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4,const StringHolder & s5,const StringHolder & s6,const StringHolder & s7)284 string StrCat(const StringHolder& s1, const StringHolder& s2,
285 const StringHolder& s3, const StringHolder& s4,
286 const StringHolder& s5, const StringHolder& s6,
287 const StringHolder& s7) {
288 string result;
289 result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() +
290 s5.Length() + s6.Length() + s7.Length() + 1);
291 result += s1;
292 result += s2;
293 result += s3;
294 result += s4;
295 result += s5;
296 result += s6;
297 result += s7;
298
299 return result;
300 }
301
StrCat(const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4,const StringHolder & s5,const StringHolder & s6,const StringHolder & s7,const StringHolder & s8)302 string StrCat(const StringHolder& s1, const StringHolder& s2,
303 const StringHolder& s3, const StringHolder& s4,
304 const StringHolder& s5, const StringHolder& s6,
305 const StringHolder& s7, const StringHolder& s8) {
306 string result;
307 result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() +
308 s5.Length() + s6.Length() + s7.Length() + s8.Length() + 1);
309 result += s1;
310 result += s2;
311 result += s3;
312 result += s4;
313 result += s5;
314 result += s6;
315 result += s7;
316 result += s8;
317
318 return result;
319 }
320
StrCat(const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4,const StringHolder & s5,const StringHolder & s6,const StringHolder & s7,const StringHolder & s8,const StringHolder & s9)321 string StrCat(const StringHolder& s1, const StringHolder& s2,
322 const StringHolder& s3, const StringHolder& s4,
323 const StringHolder& s5, const StringHolder& s6,
324 const StringHolder& s7, const StringHolder& s8,
325 const StringHolder& s9) {
326 string result;
327 result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() +
328 s5.Length() + s6.Length() + s7.Length() + s8.Length() +
329 s9.Length() + 1);
330 result += s1;
331 result += s2;
332 result += s3;
333 result += s4;
334 result += s5;
335 result += s6;
336 result += s7;
337 result += s8;
338 result += s9;
339
340 return result;
341 }
342
StrCat(const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4,const StringHolder & s5,const StringHolder & s6,const StringHolder & s7,const StringHolder & s8,const StringHolder & s9,const StringHolder & s10,const StringHolder & s11)343 string StrCat(const StringHolder& s1, const StringHolder& s2,
344 const StringHolder& s3, const StringHolder& s4,
345 const StringHolder& s5, const StringHolder& s6,
346 const StringHolder& s7, const StringHolder& s8,
347 const StringHolder& s9, const StringHolder& s10,
348 const StringHolder& s11) {
349 string result;
350 result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() +
351 s5.Length() + s6.Length() + s7.Length() + s8.Length() +
352 s9.Length() + s10.Length() + s11.Length());
353 result += s1;
354 result += s2;
355 result += s3;
356 result += s4;
357 result += s5;
358 result += s6;
359 result += s7;
360 result += s8;
361 result += s9;
362 result += s10;
363 result += s11;
364
365 return result;
366 }
367
StrCat(const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4,const StringHolder & s5,const StringHolder & s6,const StringHolder & s7,const StringHolder & s8,const StringHolder & s9,const StringHolder & s10,const StringHolder & s11,const StringHolder & s12)368 string StrCat(const StringHolder& s1, const StringHolder& s2,
369 const StringHolder& s3, const StringHolder& s4,
370 const StringHolder& s5, const StringHolder& s6,
371 const StringHolder& s7, const StringHolder& s8,
372 const StringHolder& s9, const StringHolder& s10,
373 const StringHolder& s11, const StringHolder& s12) {
374 string result;
375 result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() +
376 s5.Length() + s6.Length() + s7.Length() + s8.Length() +
377 s9.Length() + s10.Length() + s11.Length() + s12.Length());
378 result += s1;
379 result += s2;
380 result += s3;
381 result += s4;
382 result += s5;
383 result += s6;
384 result += s7;
385 result += s8;
386 result += s9;
387 result += s10;
388 result += s11;
389 result += s12;
390
391 return result;
392 }
393
StrCat(const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4,const StringHolder & s5,const StringHolder & s6,const StringHolder & s7,const StringHolder & s8,const StringHolder & s9,const StringHolder & s10,const StringHolder & s11,const StringHolder & s12,const StringHolder & s13)394 string StrCat(const StringHolder& s1, const StringHolder& s2,
395 const StringHolder& s3, const StringHolder& s4,
396 const StringHolder& s5, const StringHolder& s6,
397 const StringHolder& s7, const StringHolder& s8,
398 const StringHolder& s9, const StringHolder& s10,
399 const StringHolder& s11, const StringHolder& s12,
400 const StringHolder& s13) {
401 string result;
402 result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() +
403 s5.Length() + s6.Length() + s7.Length() + s8.Length() +
404 s9.Length() + s10.Length() + s11.Length() + s12.Length() +
405 s13.Length());
406 result += s1;
407 result += s2;
408 result += s3;
409 result += s4;
410 result += s5;
411 result += s6;
412 result += s7;
413 result += s8;
414 result += s9;
415 result += s10;
416 result += s11;
417 result += s12;
418 result += s13;
419
420 return result;
421 }
422
StrCat(const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4,const StringHolder & s5,const StringHolder & s6,const StringHolder & s7,const StringHolder & s8,const StringHolder & s9,const StringHolder & s10,const StringHolder & s11,const StringHolder & s12,const StringHolder & s13,const StringHolder & s14)423 string StrCat(const StringHolder& s1, const StringHolder& s2,
424 const StringHolder& s3, const StringHolder& s4,
425 const StringHolder& s5, const StringHolder& s6,
426 const StringHolder& s7, const StringHolder& s8,
427 const StringHolder& s9, const StringHolder& s10,
428 const StringHolder& s11, const StringHolder& s12,
429 const StringHolder& s13, const StringHolder& s14) {
430 string result;
431 result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() +
432 s5.Length() + s6.Length() + s7.Length() + s8.Length() +
433 s9.Length() + s10.Length() + s11.Length() + s12.Length() +
434 s13.Length() + s14.Length());
435 result += s1;
436 result += s2;
437 result += s3;
438 result += s4;
439 result += s5;
440 result += s6;
441 result += s7;
442 result += s8;
443 result += s9;
444 result += s10;
445 result += s11;
446 result += s12;
447 result += s13;
448 result += s14;
449
450 return result;
451 }
452
StrCat(const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4,const StringHolder & s5,const StringHolder & s6,const StringHolder & s7,const StringHolder & s8,const StringHolder & s9,const StringHolder & s10,const StringHolder & s11,const StringHolder & s12,const StringHolder & s13,const StringHolder & s14,const StringHolder & s15)453 string StrCat(const StringHolder& s1, const StringHolder& s2,
454 const StringHolder& s3, const StringHolder& s4,
455 const StringHolder& s5, const StringHolder& s6,
456 const StringHolder& s7, const StringHolder& s8,
457 const StringHolder& s9, const StringHolder& s10,
458 const StringHolder& s11, const StringHolder& s12,
459 const StringHolder& s13, const StringHolder& s14,
460 const StringHolder& s15) {
461 string result;
462 result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() +
463 s5.Length() + s6.Length() + s7.Length() + s8.Length() +
464 s9.Length() + s10.Length() + s11.Length() + s12.Length() +
465 s13.Length() + s14.Length() + s15.Length());
466 result += s1;
467 result += s2;
468 result += s3;
469 result += s4;
470 result += s5;
471 result += s6;
472 result += s7;
473 result += s8;
474 result += s9;
475 result += s10;
476 result += s11;
477 result += s12;
478 result += s13;
479 result += s14;
480 result += s15;
481
482 return result;
483 }
484
StrCat(const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4,const StringHolder & s5,const StringHolder & s6,const StringHolder & s7,const StringHolder & s8,const StringHolder & s9,const StringHolder & s10,const StringHolder & s11,const StringHolder & s12,const StringHolder & s13,const StringHolder & s14,const StringHolder & s15,const StringHolder & s16)485 string StrCat(const StringHolder& s1, const StringHolder& s2,
486 const StringHolder& s3, const StringHolder& s4,
487 const StringHolder& s5, const StringHolder& s6,
488 const StringHolder& s7, const StringHolder& s8,
489 const StringHolder& s9, const StringHolder& s10,
490 const StringHolder& s11, const StringHolder& s12,
491 const StringHolder& s13, const StringHolder& s14,
492 const StringHolder& s15, const StringHolder& s16) {
493 string result;
494 result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() +
495 s5.Length() + s6.Length() + s7.Length() + s8.Length() +
496 s9.Length() + s10.Length() + s11.Length() + s12.Length() +
497 s13.Length() + s14.Length() + s15.Length() + s16.Length());
498 result += s1;
499 result += s2;
500 result += s3;
501 result += s4;
502 result += s5;
503 result += s6;
504 result += s7;
505 result += s8;
506 result += s9;
507 result += s10;
508 result += s11;
509 result += s12;
510 result += s13;
511 result += s14;
512 result += s15;
513 result += s16;
514
515 return result;
516 }
517
518 // StrAppend
519
StrAppend(string * dest,const StringHolder & s1)520 void StrAppend(string* dest, const StringHolder& s1) {
521 assert(dest);
522
523 dest->reserve(dest->length() + s1.Length() + 1);
524 *dest += s1;
525 }
526
StrAppend(string * dest,const StringHolder & s1,const StringHolder & s2)527 void StrAppend(string* dest, const StringHolder& s1, const StringHolder& s2) {
528 assert(dest);
529
530 dest->reserve(dest->length() + s1.Length() + s2.Length() + 1);
531 *dest += s1;
532 *dest += s2;
533 }
534
StrAppend(string * dest,const StringHolder & s1,const StringHolder & s2,const StringHolder & s3)535 void StrAppend(string* dest, const StringHolder& s1, const StringHolder& s2,
536 const StringHolder& s3) {
537 assert(dest);
538
539 dest->reserve(dest->length() + s1.Length() + s2.Length() + s3.Length() + 1);
540 *dest += s1;
541 *dest += s2;
542 *dest += s3;
543 }
544
StrAppend(string * dest,const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4)545 void StrAppend(string* dest, const StringHolder& s1, const StringHolder& s2,
546 const StringHolder& s3, const StringHolder& s4) {
547 assert(dest);
548
549 dest->reserve(dest->length() + s1.Length() + s2.Length() + s3.Length() +
550 s4.Length() + 1);
551 *dest += s1;
552 *dest += s2;
553 *dest += s3;
554 *dest += s4;
555 }
556
StrAppend(string * dest,const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4,const StringHolder & s5)557 void StrAppend(string* dest, const StringHolder& s1, const StringHolder& s2,
558 const StringHolder& s3, const StringHolder& s4,
559 const StringHolder& s5) {
560 assert(dest);
561
562 dest->reserve(dest->length() + s1.Length() + s2.Length() + s3.Length() +
563 s4.Length() + s5.Length() + 1);
564 *dest += s1;
565 *dest += s2;
566 *dest += s3;
567 *dest += s4;
568 *dest += s5;
569 }
570
571 } // namespace phonenumbers
572 } // namespace i18n
573