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 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> 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 51 string SimpleItoa(int n) { 52 return GenericSimpleItoa(n); 53 } 54 55 string SimpleItoa(uint64 n) { 56 return GenericSimpleItoa(n); 57 } 58 59 string SimpleItoa(int64 n) { 60 return GenericSimpleItoa(n); 61 } 62 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 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 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 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 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 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> 126 void GenericAtoi(const string& s, T* out) { 127 stringstream stream; 128 stream << s; 129 stream >> *out; 130 } 131 132 void safe_strto32(const string& s, int32 *n) { 133 GenericAtoi(s, n); 134 } 135 136 void safe_strtou64(const string& s, uint64 *n) { 137 GenericAtoi(s, n); 138 } 139 140 void safe_strto64(const string& s, int64* n) { 141 GenericAtoi(s, n); 142 } 143 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 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 182 StringHolder::StringHolder(const string& s) 183 : string_(&s), 184 cstring_(NULL), 185 len_(s.size()) 186 {} 187 188 StringHolder::StringHolder(const char* s) 189 : string_(NULL), 190 cstring_(s), 191 len_(std::strlen(s)) 192 {} 193 194 StringHolder::StringHolder(uint64 n) 195 : converted_string_(SimpleItoa(n)), 196 string_(&converted_string_), 197 cstring_(NULL), 198 len_(converted_string_.length()) 199 {} 200 201 StringHolder::~StringHolder() {} 202 203 // StrCat 204 205 // Implements s += sh; (s: string, sh: StringHolder) 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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