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
394 // StrAppend
395
StrAppend(string * dest,const StringHolder & s1)396 void StrAppend(string* dest, const StringHolder& s1) {
397 assert(dest);
398
399 dest->reserve(dest->length() + s1.Length() + 1);
400 *dest += s1;
401 }
402
StrAppend(string * dest,const StringHolder & s1,const StringHolder & s2)403 void StrAppend(string* dest, const StringHolder& s1, const StringHolder& s2) {
404 assert(dest);
405
406 dest->reserve(dest->length() + s1.Length() + s2.Length() + 1);
407 *dest += s1;
408 *dest += s2;
409 }
410
StrAppend(string * dest,const StringHolder & s1,const StringHolder & s2,const StringHolder & s3)411 void StrAppend(string* dest, const StringHolder& s1, const StringHolder& s2,
412 const StringHolder& s3) {
413 assert(dest);
414
415 dest->reserve(dest->length() + s1.Length() + s2.Length() + s3.Length() + 1);
416 *dest += s1;
417 *dest += s2;
418 *dest += s3;
419 }
420
StrAppend(string * dest,const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4)421 void StrAppend(string* dest, const StringHolder& s1, const StringHolder& s2,
422 const StringHolder& s3, const StringHolder& s4) {
423 assert(dest);
424
425 dest->reserve(dest->length() + s1.Length() + s2.Length() + s3.Length() +
426 s4.Length() + 1);
427 *dest += s1;
428 *dest += s2;
429 *dest += s3;
430 *dest += s4;
431 }
432
StrAppend(string * dest,const StringHolder & s1,const StringHolder & s2,const StringHolder & s3,const StringHolder & s4,const StringHolder & s5)433 void StrAppend(string* dest, const StringHolder& s1, const StringHolder& s2,
434 const StringHolder& s3, const StringHolder& s4,
435 const StringHolder& s5) {
436 assert(dest);
437
438 dest->reserve(dest->length() + s1.Length() + s2.Length() + s3.Length() +
439 s4.Length() + s5.Length() + 1);
440 *dest += s1;
441 *dest += s2;
442 *dest += s3;
443 *dest += s4;
444 *dest += s5;
445 }
446
447 } // namespace phonenumbers
448 } // namespace i18n
449