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