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 #include "phonenumbers/asyoutypeformatter.h" 16 17 #include <cctype> 18 #include <list> 19 #include <string> 20 21 #include <google/protobuf/message_lite.h> 22 23 #include "phonenumbers/base/logging.h" 24 #include "phonenumbers/base/memory/scoped_ptr.h" 25 #include "phonenumbers/phonemetadata.pb.h" 26 #include "phonenumbers/phonenumberutil.h" 27 #include "phonenumbers/regexp_cache.h" 28 #include "phonenumbers/regexp_factory.h" 29 #include "phonenumbers/stringutil.h" 30 #include "phonenumbers/unicodestring.h" 31 32 namespace i18n { 33 namespace phonenumbers { 34 35 using google::protobuf::RepeatedPtrField; 36 37 namespace { 38 39 const char kPlusSign = '+'; 40 41 // A pattern that is used to match character classes in regular expressions. 42 // An example of a character class is [1-4]. 43 const char kCharacterClassPattern[] = "\\[([^\\[\\]])*\\]"; 44 45 // This is the minimum length of national number accrued that is required to 46 // trigger the formatter. The first element of the leading_digits_pattern of 47 // each number_format contains a regular expression that matches up to this 48 // number of digits. 49 const size_t kMinLeadingDigitsLength = 3; 50 51 // The digits that have not been entered yet will be represented by a \u2008, 52 // the punctuation space. 53 const char kDigitPlaceholder[] = "\xE2\x80\x88"; /* "" */ 54 55 // Character used when appropriate to separate a prefix, such as a long NDD or a 56 // country calling code, from the national number. 57 const char kSeparatorBeforeNationalNumber = ' '; 58 59 // A set of characters that, if found in a national prefix formatting rules, are 60 // an indicator to us that we should separate the national prefix from the 61 // number when formatting. 62 const char kNationalPrefixSeparatorsPattern[] = "[- ]"; 63 64 // Replaces any standalone digit in the pattern (not any inside a {} grouping) 65 // with \d. This function replaces the standalone digit regex used in the Java 66 // version which is currently not supported by RE2 because it uses a special 67 // construct (?=). 68 void ReplacePatternDigits(string* pattern) { 69 DCHECK(pattern); 70 string new_pattern; 71 72 for (string::const_iterator it = pattern->begin(); it != pattern->end(); 73 ++it) { 74 const char current_char = *it; 75 76 if (isdigit(current_char)) { 77 if (it + 1 != pattern->end()) { 78 const char next_char = it[1]; 79 80 if (next_char != ',' && next_char != '}') { 81 new_pattern += "\\d"; 82 } else { 83 new_pattern += current_char; 84 } 85 } else { 86 new_pattern += "\\d"; 87 } 88 } else { 89 new_pattern += current_char; 90 } 91 } 92 pattern->assign(new_pattern); 93 } 94 95 // Matches all the groups contained in 'input' against 'pattern'. 96 void MatchAllGroups(const string& pattern, 97 const string& input, 98 const AbstractRegExpFactory& regexp_factory, 99 RegExpCache* cache, 100 string* group) { 101 DCHECK(cache); 102 DCHECK(group); 103 string new_pattern(pattern); 104 105 // Transforms pattern "(...)(...)(...)" to "(.........)". 106 strrmm(&new_pattern, "()"); 107 new_pattern = StrCat("(", new_pattern, ")"); 108 109 const scoped_ptr<RegExpInput> consume_input( 110 regexp_factory.CreateInput(input)); 111 bool status = 112 cache->GetRegExp(new_pattern).Consume(consume_input.get(), group); 113 DCHECK(status); 114 } 115 116 PhoneMetadata CreateEmptyMetadata() { 117 PhoneMetadata metadata; 118 metadata.set_international_prefix("NA"); 119 return metadata; 120 } 121 122 } // namespace 123 124 AsYouTypeFormatter::AsYouTypeFormatter(const string& region_code) 125 : regexp_factory_(new RegExpFactory()), 126 regexp_cache_(*regexp_factory_.get(), 64), 127 current_output_(), 128 formatting_template_(), 129 current_formatting_pattern_(), 130 accrued_input_(), 131 accrued_input_without_formatting_(), 132 able_to_format_(true), 133 input_has_formatting_(false), 134 is_complete_number_(false), 135 is_expecting_country_code_(false), 136 phone_util_(*PhoneNumberUtil::GetInstance()), 137 default_country_(region_code), 138 empty_metadata_(CreateEmptyMetadata()), 139 default_metadata_(GetMetadataForRegion(region_code)), 140 current_metadata_(default_metadata_), 141 last_match_position_(0), 142 original_position_(0), 143 position_to_remember_(0), 144 prefix_before_national_number_(), 145 should_add_space_after_national_prefix_(false), 146 national_prefix_extracted_(), 147 national_number_(), 148 possible_formats_() { 149 } 150 151 // The metadata needed by this class is the same for all regions sharing the 152 // same country calling code. Therefore, we return the metadata for "main" 153 // region for this country calling code. 154 const PhoneMetadata* AsYouTypeFormatter::GetMetadataForRegion( 155 const string& region_code) const { 156 int country_calling_code = phone_util_.GetCountryCodeForRegion(region_code); 157 string main_country; 158 phone_util_.GetRegionCodeForCountryCode(country_calling_code, &main_country); 159 const PhoneMetadata* const metadata = 160 phone_util_.GetMetadataForRegion(main_country); 161 if (metadata) { 162 return metadata; 163 } 164 // Set to a default instance of the metadata. This allows us to function with 165 // an incorrect region code, even if formatting only works for numbers 166 // specified with "+". 167 return &empty_metadata_; 168 } 169 170 bool AsYouTypeFormatter::MaybeCreateNewTemplate() { 171 // When there are multiple available formats, the formatter uses the first 172 // format where a formatting template could be created. 173 for (list<const NumberFormat*>::const_iterator it = possible_formats_.begin(); 174 it != possible_formats_.end(); ++it) { 175 DCHECK(*it); 176 const NumberFormat& number_format = **it; 177 const string& pattern = number_format.pattern(); 178 if (current_formatting_pattern_ == pattern) { 179 return false; 180 } 181 if (CreateFormattingTemplate(number_format)) { 182 current_formatting_pattern_ = pattern; 183 SetShouldAddSpaceAfterNationalPrefix(number_format); 184 // With a new formatting template, the matched position using the old 185 // template needs to be reset. 186 last_match_position_ = 0; 187 return true; 188 } 189 } 190 able_to_format_ = false; 191 return false; 192 } 193 194 void AsYouTypeFormatter::GetAvailableFormats( 195 const string& leading_three_digits) { 196 const RepeatedPtrField<NumberFormat>& format_list = 197 (is_complete_number_ && 198 current_metadata_->intl_number_format().size() > 0) 199 ? current_metadata_->intl_number_format() 200 : current_metadata_->number_format(); 201 bool national_prefix_used_by_country = 202 current_metadata_->has_national_prefix(); 203 for (RepeatedPtrField<NumberFormat>::const_iterator it = format_list.begin(); 204 it != format_list.end(); ++it) { 205 if (!national_prefix_used_by_country || is_complete_number_ || 206 it->national_prefix_optional_when_formatting() || 207 phone_util_.FormattingRuleHasFirstGroupOnly( 208 it->national_prefix_formatting_rule())) { 209 if (phone_util_.IsFormatEligibleForAsYouTypeFormatter(it->format())) { 210 possible_formats_.push_back(&*it); 211 } 212 } 213 } 214 NarrowDownPossibleFormats(leading_three_digits); 215 } 216 217 void AsYouTypeFormatter::NarrowDownPossibleFormats( 218 const string& leading_digits) { 219 const int index_of_leading_digits_pattern = 220 leading_digits.length() - kMinLeadingDigitsLength; 221 222 for (list<const NumberFormat*>::iterator it = possible_formats_.begin(); 223 it != possible_formats_.end(); ) { 224 DCHECK(*it); 225 const NumberFormat& format = **it; 226 227 if (format.leading_digits_pattern_size() > 228 index_of_leading_digits_pattern) { 229 const scoped_ptr<RegExpInput> input( 230 regexp_factory_->CreateInput(leading_digits)); 231 if (!regexp_cache_.GetRegExp(format.leading_digits_pattern().Get( 232 index_of_leading_digits_pattern)).Consume(input.get())) { 233 it = possible_formats_.erase(it); 234 continue; 235 } 236 } // else the particular format has no more specific leadingDigitsPattern, 237 // and it should be retained. 238 ++it; 239 } 240 } 241 242 void AsYouTypeFormatter::SetShouldAddSpaceAfterNationalPrefix( 243 const NumberFormat& format) { 244 static const scoped_ptr<const RegExp> national_prefix_separators_pattern( 245 regexp_factory_->CreateRegExp(kNationalPrefixSeparatorsPattern)); 246 should_add_space_after_national_prefix_ = 247 national_prefix_separators_pattern->PartialMatch( 248 format.national_prefix_formatting_rule()); 249 } 250 251 bool AsYouTypeFormatter::CreateFormattingTemplate(const NumberFormat& format) { 252 string number_pattern = format.pattern(); 253 254 // The formatter doesn't format numbers when numberPattern contains "|", e.g. 255 // (20|3)\d{4}. In those cases we quickly return. 256 if (number_pattern.find('|') != string::npos) { 257 return false; 258 } 259 // Replace anything in the form of [..] with \d. 260 static const scoped_ptr<const RegExp> character_class_pattern( 261 regexp_factory_->CreateRegExp(kCharacterClassPattern)); 262 character_class_pattern->GlobalReplace(&number_pattern, "\\\\d"); 263 264 // Replace any standalone digit (not the one in d{}) with \d. 265 ReplacePatternDigits(&number_pattern); 266 267 string number_format = format.format(); 268 formatting_template_.remove(); 269 UnicodeString temp_template; 270 GetFormattingTemplate(number_pattern, number_format, &temp_template); 271 272 if (temp_template.length() > 0) { 273 formatting_template_.append(temp_template); 274 return true; 275 } 276 return false; 277 } 278 279 void AsYouTypeFormatter::GetFormattingTemplate( 280 const string& number_pattern, 281 const string& number_format, 282 UnicodeString* formatting_template) { 283 DCHECK(formatting_template); 284 285 // Creates a phone number consisting only of the digit 9 that matches the 286 // number_pattern by applying the pattern to the longest_phone_number string. 287 static const char longest_phone_number[] = "999999999999999"; 288 string a_phone_number; 289 290 MatchAllGroups(number_pattern, longest_phone_number, *regexp_factory_, 291 ®exp_cache_, &a_phone_number); 292 // No formatting template can be created if the number of digits entered so 293 // far is longer than the maximum the current formatting rule can accommodate. 294 if (a_phone_number.length() < national_number_.length()) { 295 formatting_template->remove(); 296 return; 297 } 298 // Formats the number according to number_format. 299 regexp_cache_.GetRegExp(number_pattern).GlobalReplace( 300 &a_phone_number, number_format); 301 // Replaces each digit with character kDigitPlaceholder. 302 GlobalReplaceSubstring("9", kDigitPlaceholder, &a_phone_number); 303 formatting_template->setTo(a_phone_number.c_str(), a_phone_number.size()); 304 } 305 306 void AsYouTypeFormatter::Clear() { 307 current_output_.clear(); 308 accrued_input_.remove(); 309 accrued_input_without_formatting_.remove(); 310 formatting_template_.remove(); 311 last_match_position_ = 0; 312 current_formatting_pattern_.clear(); 313 prefix_before_national_number_.clear(); 314 national_prefix_extracted_.clear(); 315 national_number_.clear(); 316 able_to_format_ = true; 317 input_has_formatting_ = false; 318 position_to_remember_ = 0; 319 original_position_ = 0; 320 is_complete_number_ = false; 321 is_expecting_country_code_ = false; 322 possible_formats_.clear(); 323 should_add_space_after_national_prefix_ = false; 324 325 if (current_metadata_ != default_metadata_) { 326 current_metadata_ = GetMetadataForRegion(default_country_); 327 } 328 } 329 330 const string& AsYouTypeFormatter::InputDigit(char32 next_char, string* result) { 331 DCHECK(result); 332 333 InputDigitWithOptionToRememberPosition(next_char, false, ¤t_output_); 334 result->assign(current_output_); 335 return *result; 336 } 337 338 const string& AsYouTypeFormatter::InputDigitAndRememberPosition( 339 char32 next_char, 340 string* result) { 341 DCHECK(result); 342 343 InputDigitWithOptionToRememberPosition(next_char, true, ¤t_output_); 344 result->assign(current_output_); 345 return *result; 346 } 347 348 void AsYouTypeFormatter::InputDigitWithOptionToRememberPosition( 349 char32 next_char, 350 bool remember_position, 351 string* phone_number) { 352 DCHECK(phone_number); 353 354 accrued_input_.append(next_char); 355 if (remember_position) { 356 original_position_ = accrued_input_.length(); 357 } 358 // We do formatting on-the-fly only when each character entered is either a 359 // plus sign (accepted at the start of the number only). 360 string next_char_string; 361 UnicodeString(next_char).toUTF8String(next_char_string); 362 363 char normalized_next_char = '\0'; 364 if (!(phone_util_.ContainsOnlyValidDigits(next_char_string) || 365 (accrued_input_.length() == 1 && next_char == kPlusSign))) { 366 able_to_format_ = false; 367 input_has_formatting_ = true; 368 } else { 369 normalized_next_char = 370 NormalizeAndAccrueDigitsAndPlusSign(next_char, remember_position); 371 } 372 if (!able_to_format_) { 373 // When we are unable to format because of reasons other than that 374 // formatting chars have been entered, it can be due to really long IDDs or 375 // NDDs. If that is the case, we might be able to do formatting again after 376 // extracting them. 377 if (input_has_formatting_) { 378 phone_number->clear(); 379 accrued_input_.toUTF8String(*phone_number); 380 } else if (AttemptToExtractIdd()) { 381 if (AttemptToExtractCountryCode()) { 382 AttemptToChoosePatternWithPrefixExtracted(phone_number); 383 return; 384 } 385 } else if (AbleToExtractLongerNdd()) { 386 // Add an additional space to separate long NDD and national significant 387 // number for readability. We don't set 388 // should_add_space_after_national_prefix_ to true, since we don't want 389 // this to change later when we choose formatting templates. 390 prefix_before_national_number_.push_back(kSeparatorBeforeNationalNumber); 391 AttemptToChoosePatternWithPrefixExtracted(phone_number); 392 return; 393 } 394 phone_number->clear(); 395 accrued_input_.toUTF8String(*phone_number); 396 return; 397 } 398 399 // We start to attempt to format only when at least kMinLeadingDigitsLength 400 // digits (the plus sign is counted as a digit as well for this purpose) have 401 // been entered. 402 switch (accrued_input_without_formatting_.length()) { 403 case 0: 404 case 1: 405 case 2: 406 phone_number->clear(); 407 accrued_input_.toUTF8String(*phone_number); 408 return; 409 case 3: 410 if (AttemptToExtractIdd()) { 411 is_expecting_country_code_ = true; 412 } else { 413 // No IDD or plus sign is found, might be entering in national format. 414 RemoveNationalPrefixFromNationalNumber(&national_prefix_extracted_); 415 AttemptToChooseFormattingPattern(phone_number); 416 return; 417 } 418 default: 419 if (is_expecting_country_code_) { 420 if (AttemptToExtractCountryCode()) { 421 is_expecting_country_code_ = false; 422 } 423 phone_number->assign(prefix_before_national_number_); 424 phone_number->append(national_number_); 425 return; 426 } 427 if (possible_formats_.size() > 0) { 428 // The formatting pattern is already chosen. 429 string temp_national_number; 430 InputDigitHelper(normalized_next_char, &temp_national_number); 431 // See if accrued digits can be formatted properly already. If not, use 432 // the results from InputDigitHelper, which does formatting based on the 433 // formatting pattern chosen. 434 string formatted_number; 435 AttemptToFormatAccruedDigits(&formatted_number); 436 if (formatted_number.length() > 0) { 437 phone_number->assign(formatted_number); 438 return; 439 } 440 NarrowDownPossibleFormats(national_number_); 441 if (MaybeCreateNewTemplate()) { 442 InputAccruedNationalNumber(phone_number); 443 return; 444 } 445 if (able_to_format_) { 446 AppendNationalNumber(temp_national_number, phone_number); 447 } else { 448 phone_number->clear(); 449 accrued_input_.toUTF8String(*phone_number); 450 } 451 return; 452 } else { 453 AttemptToChooseFormattingPattern(phone_number); 454 } 455 } 456 } 457 458 void AsYouTypeFormatter::AttemptToChoosePatternWithPrefixExtracted( 459 string* formatted_number) { 460 able_to_format_ = true; 461 is_expecting_country_code_ = false; 462 possible_formats_.clear(); 463 AttemptToChooseFormattingPattern(formatted_number); 464 } 465 466 bool AsYouTypeFormatter::AbleToExtractLongerNdd() { 467 if (national_prefix_extracted_.length() > 0) { 468 // Put the extracted NDD back to the national number before attempting to 469 // extract a new NDD. 470 national_number_.insert(0, national_prefix_extracted_); 471 // Remove the previously extracted NDD from prefixBeforeNationalNumber. We 472 // cannot simply set it to empty string because people sometimes incorrectly 473 // enter national prefix after the country code, e.g. +44 (0)20-1234-5678. 474 int index_of_previous_ndd = 475 prefix_before_national_number_.find_last_of(national_prefix_extracted_); 476 prefix_before_national_number_.resize(index_of_previous_ndd); 477 } 478 string new_national_prefix; 479 RemoveNationalPrefixFromNationalNumber(&new_national_prefix); 480 return national_prefix_extracted_ != new_national_prefix; 481 } 482 483 void AsYouTypeFormatter::AttemptToFormatAccruedDigits( 484 string* formatted_result) { 485 DCHECK(formatted_result); 486 487 for (list<const NumberFormat*>::const_iterator it = possible_formats_.begin(); 488 it != possible_formats_.end(); ++it) { 489 DCHECK(*it); 490 const NumberFormat& number_format = **it; 491 const string& pattern = number_format.pattern(); 492 493 if (regexp_cache_.GetRegExp(pattern).FullMatch(national_number_)) { 494 SetShouldAddSpaceAfterNationalPrefix(number_format); 495 496 string formatted_number(national_number_); 497 bool status = regexp_cache_.GetRegExp(pattern).GlobalReplace( 498 &formatted_number, number_format.format()); 499 DCHECK(status); 500 501 AppendNationalNumber(formatted_number, formatted_result); 502 return; 503 } 504 } 505 } 506 507 int AsYouTypeFormatter::GetRememberedPosition() const { 508 UnicodeString current_output(current_output_.c_str()); 509 if (!able_to_format_) { 510 return ConvertUnicodeStringPosition(current_output, original_position_); 511 } 512 int accrued_input_index = 0; 513 int current_output_index = 0; 514 515 while (accrued_input_index < position_to_remember_ && 516 current_output_index < current_output.length()) { 517 if (accrued_input_without_formatting_[accrued_input_index] == 518 current_output[current_output_index]) { 519 ++accrued_input_index; 520 } 521 ++current_output_index; 522 } 523 return ConvertUnicodeStringPosition(current_output, current_output_index); 524 } 525 526 void AsYouTypeFormatter::AppendNationalNumber(const string& national_number, 527 string* phone_number) const { 528 int prefix_before_national_number_length = 529 prefix_before_national_number_.size(); 530 if (should_add_space_after_national_prefix_ && 531 prefix_before_national_number_length > 0 && 532 prefix_before_national_number_.at( 533 prefix_before_national_number_length - 1) != 534 kSeparatorBeforeNationalNumber) { 535 // We want to add a space after the national prefix if the national prefix 536 // formatting rule indicates that this would normally be done, with the 537 // exception of the case where we already appended a space because the NDD 538 // was surprisingly long. 539 phone_number->assign(prefix_before_national_number_); 540 phone_number->push_back(kSeparatorBeforeNationalNumber); 541 StrAppend(phone_number, national_number); 542 } else { 543 phone_number->assign( 544 StrCat(prefix_before_national_number_, national_number)); 545 } 546 } 547 548 void AsYouTypeFormatter::AttemptToChooseFormattingPattern( 549 string* formatted_number) { 550 DCHECK(formatted_number); 551 552 if (national_number_.length() >= kMinLeadingDigitsLength) { 553 const string leading_digits = 554 national_number_.substr(0, kMinLeadingDigitsLength); 555 556 GetAvailableFormats(leading_digits); 557 if (MaybeCreateNewTemplate()) { 558 InputAccruedNationalNumber(formatted_number); 559 } else { 560 formatted_number->clear(); 561 accrued_input_.toUTF8String(*formatted_number); 562 } 563 return; 564 } else { 565 AppendNationalNumber(national_number_, formatted_number); 566 } 567 } 568 569 void AsYouTypeFormatter::InputAccruedNationalNumber(string* number) { 570 DCHECK(number); 571 int length_of_national_number = national_number_.length(); 572 573 if (length_of_national_number > 0) { 574 string temp_national_number; 575 576 for (int i = 0; i < length_of_national_number; ++i) { 577 temp_national_number.clear(); 578 InputDigitHelper(national_number_[i], &temp_national_number); 579 } 580 if (able_to_format_) { 581 AppendNationalNumber(temp_national_number, number); 582 } else { 583 number->clear(); 584 accrued_input_.toUTF8String(*number); 585 } 586 return; 587 } else { 588 number->assign(prefix_before_national_number_); 589 } 590 } 591 592 bool AsYouTypeFormatter::IsNanpaNumberWithNationalPrefix() const { 593 // For NANPA numbers beginning with 1[2-9], treat the 1 as the national 594 // prefix. The reason is that national significant numbers in NANPA always 595 // start with [2-9] after the national prefix. Numbers beginning with 1[01] 596 // can only be short/emergency numbers, which don't need the national 597 // prefix. 598 return (current_metadata_->country_code() == 1) && 599 (national_number_[0] == '1') && (national_number_[1] != '0') && 600 (national_number_[1] != '1'); 601 } 602 603 void AsYouTypeFormatter::RemoveNationalPrefixFromNationalNumber( 604 string* national_prefix) { 605 int start_of_national_number = 0; 606 607 if (IsNanpaNumberWithNationalPrefix()) { 608 start_of_national_number = 1; 609 prefix_before_national_number_.append("1"); 610 prefix_before_national_number_.push_back(kSeparatorBeforeNationalNumber); 611 is_complete_number_ = true; 612 } else if (current_metadata_->has_national_prefix_for_parsing()) { 613 const scoped_ptr<RegExpInput> consumed_input( 614 regexp_factory_->CreateInput(national_number_)); 615 const RegExp& pattern = regexp_cache_.GetRegExp( 616 current_metadata_->national_prefix_for_parsing()); 617 618 if (pattern.Consume(consumed_input.get())) { 619 // When the national prefix is detected, we use international formatting 620 // rules instead of national ones, because national formatting rules could 621 // countain local formatting rules for numbers entered without area code. 622 is_complete_number_ = true; 623 start_of_national_number = 624 national_number_.length() - consumed_input->ToString().length(); 625 prefix_before_national_number_.append( 626 national_number_.substr(0, start_of_national_number)); 627 } 628 } 629 national_prefix->assign(national_number_, 0, start_of_national_number); 630 national_number_.erase(0, start_of_national_number); 631 } 632 633 bool AsYouTypeFormatter::AttemptToExtractIdd() { 634 string accrued_input_without_formatting_stdstring; 635 accrued_input_without_formatting_ 636 .toUTF8String(accrued_input_without_formatting_stdstring); 637 const scoped_ptr<RegExpInput> consumed_input( 638 regexp_factory_->CreateInput(accrued_input_without_formatting_stdstring)); 639 const RegExp& international_prefix = regexp_cache_.GetRegExp( 640 StrCat("\\", string(&kPlusSign, 1), "|", 641 current_metadata_->international_prefix())); 642 643 if (international_prefix.Consume(consumed_input.get())) { 644 is_complete_number_ = true; 645 const int start_of_country_code = 646 accrued_input_without_formatting_.length() - 647 consumed_input->ToString().length(); 648 649 national_number_.clear(); 650 accrued_input_without_formatting_.tempSubString(start_of_country_code) 651 .toUTF8String(national_number_); 652 653 string before_country_code; 654 accrued_input_without_formatting_.tempSubString(0, start_of_country_code) 655 .toUTF8String(before_country_code); 656 prefix_before_national_number_.clear(); 657 prefix_before_national_number_.append(before_country_code); 658 659 if (accrued_input_without_formatting_[0] != kPlusSign) { 660 prefix_before_national_number_.push_back(kSeparatorBeforeNationalNumber); 661 } 662 return true; 663 } 664 return false; 665 } 666 667 bool AsYouTypeFormatter::AttemptToExtractCountryCode() { 668 if (national_number_.length() == 0) { 669 return false; 670 } 671 string number_without_country_code(national_number_); 672 int country_code = 673 phone_util_.ExtractCountryCode(&number_without_country_code); 674 if (country_code == 0) { 675 return false; 676 } 677 national_number_.assign(number_without_country_code); 678 string new_region_code; 679 phone_util_.GetRegionCodeForCountryCode(country_code, &new_region_code); 680 if (PhoneNumberUtil::kRegionCodeForNonGeoEntity == new_region_code) { 681 current_metadata_ = 682 phone_util_.GetMetadataForNonGeographicalRegion(country_code); 683 } else if (new_region_code != default_country_) { 684 current_metadata_ = GetMetadataForRegion(new_region_code); 685 } 686 StrAppend(&prefix_before_national_number_, country_code); 687 prefix_before_national_number_.push_back(kSeparatorBeforeNationalNumber); 688 689 return true; 690 } 691 692 char AsYouTypeFormatter::NormalizeAndAccrueDigitsAndPlusSign( 693 char32 next_char, 694 bool remember_position) { 695 char normalized_char = next_char; 696 697 if (next_char == kPlusSign) { 698 accrued_input_without_formatting_.append(next_char); 699 } else { 700 string number; 701 UnicodeString(next_char).toUTF8String(number); 702 phone_util_.NormalizeDigitsOnly(&number); 703 accrued_input_without_formatting_.append(next_char); 704 national_number_.append(number); 705 normalized_char = number[0]; 706 } 707 if (remember_position) { 708 position_to_remember_ = accrued_input_without_formatting_.length(); 709 } 710 return normalized_char; 711 } 712 713 void AsYouTypeFormatter::InputDigitHelper(char next_char, string* number) { 714 DCHECK(number); 715 number->clear(); 716 const char32 placeholder_codepoint = UnicodeString(kDigitPlaceholder)[0]; 717 int placeholder_pos = formatting_template_ 718 .tempSubString(last_match_position_).indexOf(placeholder_codepoint); 719 if (placeholder_pos != -1) { 720 UnicodeString temp_template = formatting_template_; 721 placeholder_pos = temp_template.indexOf(placeholder_codepoint); 722 temp_template.setCharAt(placeholder_pos, UnicodeString(next_char)[0]); 723 last_match_position_ = placeholder_pos; 724 formatting_template_.replace(0, temp_template.length(), temp_template); 725 formatting_template_.tempSubString(0, last_match_position_ + 1) 726 .toUTF8String(*number); 727 } else { 728 if (possible_formats_.size() == 1) { 729 // More digits are entered than we could handle, and there are no other 730 // valid patterns to try. 731 able_to_format_ = false; 732 } // else, we just reset the formatting pattern. 733 current_formatting_pattern_.clear(); 734 accrued_input_.toUTF8String(*number); 735 } 736 } 737 738 // Returns the number of bytes contained in the given UnicodeString up to the 739 // specified position. 740 // static 741 int AsYouTypeFormatter::ConvertUnicodeStringPosition(const UnicodeString& s, 742 int pos) { 743 if (pos > s.length()) { 744 return -1; 745 } 746 string substring; 747 s.tempSubString(0, pos).toUTF8String(substring); 748 return substring.length(); 749 } 750 751 } // namespace phonenumbers 752 } // namespace i18n 753