blob: 390ccfa34f874b90ab2a5d487f622ae1615df108 [file] [log] [blame]
Philippe Liardb59d9082011-08-18 11:41:24 +00001// Copyright (C) 2011 The Libphonenumber Authors
Philip Liarddbb360c2011-02-25 09:02:23 +00002//
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
Philippe Liard7b30af62011-09-21 17:43:54 +000017#include <algorithm>
Philip Liarddbb360c2011-02-25 09:02:23 +000018#include <cassert>
19#include <cstring>
20#include <sstream>
21
Philippe Liard32b0fe62011-07-01 08:22:06 +000022#include "phonenumbers/stringutil.h"
Philip Liarddbb360c2011-02-25 09:02:23 +000023
24namespace i18n {
25namespace phonenumbers {
26
Philippe Liard7b30af62011-09-21 17:43:54 +000027using std::equal;
Philip Liarddbb360c2011-02-25 09:02:23 +000028using std::stringstream;
29
Philippe Liard1b09e6d2012-05-23 09:20:57 +000030string operator+(const string& s, int n) { // NOLINT(runtime/string)
Philip Liard6f1ba2d2011-04-07 07:27:47 +000031 stringstream stream;
Philip Liarddbb360c2011-02-25 09:02:23 +000032
Philip Liard6f1ba2d2011-04-07 07:27:47 +000033 stream << s << n;
Philip Liarddbb360c2011-02-25 09:02:23 +000034 string result;
Philip Liard6f1ba2d2011-04-07 07:27:47 +000035 stream >> result;
Philip Liarddbb360c2011-02-25 09:02:23 +000036
37 return result;
38}
39
Philip Liardd4e1c732011-02-25 15:51:21 +000040template <typename T>
41string GenericSimpleItoa(const T& n) {
Philip Liard6f1ba2d2011-04-07 07:27:47 +000042 stringstream stream;
Philip Liarddbb360c2011-02-25 09:02:23 +000043
Philip Liard6f1ba2d2011-04-07 07:27:47 +000044 stream << n;
Philip Liarddbb360c2011-02-25 09:02:23 +000045 string result;
Philip Liard6f1ba2d2011-04-07 07:27:47 +000046 stream >> result;
Philip Liarddbb360c2011-02-25 09:02:23 +000047
48 return result;
49}
50
Philip Liardd4e1c732011-02-25 15:51:21 +000051string SimpleItoa(int n) {
52 return GenericSimpleItoa(n);
53}
54
55string SimpleItoa(uint64 n) {
56 return GenericSimpleItoa(n);
57}
58
Philippe Liard31b15982012-06-01 15:33:18 +000059string SimpleItoa(int64 n) {
60 return GenericSimpleItoa(n);
61}
62
Philippe Liard7b30af62011-09-21 17:43:54 +000063bool 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
Philip Liard6f1ba2d2011-04-07 07:27:47 +0000100void 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
Philip Liarde5786922011-04-26 09:04:58 +0000110bool 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
Philip Liard6f1ba2d2011-04-07 07:27:47 +0000125template <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}
Philip Liardd4e1c732011-02-25 15:51:21 +0000139
Philippe Liard31b15982012-06-01 15:33:18 +0000140void safe_strto64(const string& s, int64* n) {
141 GenericAtoi(s, n);
142}
143
Philip Liarde5786922011-04-26 09:04:58 +0000144void 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 }
Philip Liarddbb360c2011-02-25 09:02:23 +0000152 }
Philip Liarddbb360c2011-02-25 09:02:23 +0000153}
154
Philip Liard791ec352011-05-16 16:12:25 +0000155int 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
Philip Liarddbb360c2011-02-25 09:02:23 +0000180// StringHolder class
181
Philippe Liard1b09e6d2012-05-23 09:20:57 +0000182StringHolder::StringHolder(const string& s)
183 : string_(&s),
184 cstring_(NULL),
185 len_(s.size())
Philip Liarddbb360c2011-02-25 09:02:23 +0000186{}
187
Philippe Liard1b09e6d2012-05-23 09:20:57 +0000188StringHolder::StringHolder(const char* s)
189 : string_(NULL),
190 cstring_(s),
191 len_(std::strlen(s))
Philip Liarddbb360c2011-02-25 09:02:23 +0000192{}
193
Philippe Liard1b09e6d2012-05-23 09:20:57 +0000194StringHolder::StringHolder(uint64 n)
195 : converted_string_(SimpleItoa(n)),
196 string_(&converted_string_),
197 cstring_(NULL),
198 len_(converted_string_.length())
Philip Liard6f1ba2d2011-04-07 07:27:47 +0000199{}
200
Philip Liarddbb360c2011-02-25 09:02:23 +0000201StringHolder::~StringHolder() {}
202
203// StrCat
204
Philip Liard6f1ba2d2011-04-07 07:27:47 +0000205// Implements s += sh; (s: string, sh: StringHolder)
Philip Liarddbb360c2011-02-25 09:02:23 +0000206string& 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,
Philip Liard6f1ba2d2011-04-07 07:27:47 +0000287 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,
Philippe Liard7b30af62011-09-21 17:43:54 +0000305 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,
Philip Liarddbb360c2011-02-25 09:02:23 +0000324 const StringHolder& s7, const StringHolder& s8,
Philippe Liard4567abf2011-08-12 07:44:38 +0000325 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,
Philip Liarddbb360c2011-02-25 09:02:23 +0000347 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
Lara Scheidegger7ae82ad2012-09-06 09:48:57 +0000368string 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
Philip Liard6f1ba2d2011-04-07 07:27:47 +0000394// 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
Philippe Liarde55d3842012-03-15 17:04:03 +0000411void 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
Philip Liarddbb360c2011-02-25 09:02:23 +0000447} // namespace phonenumbers
448} // namespace i18n