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