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
24namespace i18n {
25namespace phonenumbers {
26
27using std::equal;
28using std::stringstream;
29
30string 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
40template <typename T>
41string GenericSimpleItoa(const T& n) {
42  stringstream stream;
43
44  stream << n;
45  string result;
46  stream >> result;
47
48  return result;
49}
50
51string SimpleItoa(int n) {
52  return GenericSimpleItoa(n);
53}
54
55string SimpleItoa(uint64 n) {
56  return GenericSimpleItoa(n);
57}
58
59string SimpleItoa(int64 n) {
60  return GenericSimpleItoa(n);
61}
62
63bool 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
68size_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
80void 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
100void 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
110bool 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
118bool 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
125template <typename T>
126void GenericAtoi(const string& s, T* out) {
127  stringstream stream;
128  stream << s;
129  stream >> *out;
130}
131
132void safe_strto32(const string& s, int32 *n) {
133  GenericAtoi(s, n);
134}
135
136void safe_strtou64(const string& s, uint64 *n) {
137  GenericAtoi(s, n);
138}
139
140void safe_strto64(const string& s, int64* n) {
141  GenericAtoi(s, n);
142}
143
144void 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
155int 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
182StringHolder::StringHolder(const string& s)
183  : string_(&s),
184    cstring_(NULL),
185    len_(s.size())
186{}
187
188StringHolder::StringHolder(const char* s)
189  : string_(NULL),
190    cstring_(s),
191    len_(std::strlen(s))
192{}
193
194StringHolder::StringHolder(uint64 n)
195  : converted_string_(SimpleItoa(n)),
196    string_(&converted_string_),
197    cstring_(NULL),
198    len_(converted_string_.length())
199{}
200
201StringHolder::~StringHolder() {}
202
203// StrCat
204
205// Implements s += sh; (s: string, sh: StringHolder)
206string& 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
218string 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
228string 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
240string 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
253string 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
268string 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
284string 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
302string 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
321string 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
343string 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
368string 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
396void StrAppend(string* dest, const StringHolder& s1) {
397  assert(dest);
398
399  dest->reserve(dest->length() + s1.Length() + 1);
400  *dest += s1;
401}
402
403void 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
411void 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
421void 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
433void 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