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 ®exp_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, ¤t_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, ¤t_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