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