1 // Copyright (C) 2011 The Libphonenumber Authors
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include "phonenumbers/asyoutypeformatter.h"
21 #include <google/protobuf/message_lite.h>
23 #include "base/logging.h"
24 #include "base/memory/scoped_ptr.h"
25 #include "phonenumbers/phonemetadata.pb.h"
26 #include "phonenumbers/phonenumberutil.h"
27 #include "phonenumbers/regexp_cache.h"
28 #include "phonenumbers/regexp_factory.h"
29 #include "phonenumbers/stringutil.h"
30 #include "phonenumbers/unicodestring.h"
33 namespace phonenumbers {
35 using google::protobuf::RepeatedPtrField;
39 const char kPlusSign = '+';
41 // A pattern that is used to match character classes in regular expressions.
42 // An example of a character class is [1-4].
43 const char kCharacterClassPattern[] = "\\[([^\\[\\]])*\\]";
45 // This is the minimum length of national number accrued that is required to
46 // trigger the formatter. The first element of the leading_digits_pattern of
47 // each number_format contains a regular expression that matches up to this
49 const size_t kMinLeadingDigitsLength = 3;
51 // The digits that have not been entered yet will be represented by a \u2008,
52 // the punctuation space.
53 const char kDigitPlaceholder[] = "\xE2\x80\x88"; /* " " */
55 // Character used when appropriate to separate a prefix, such as a long NDD or a
56 // country calling code, from the national number.
57 const char kSeparatorBeforeNationalNumber = ' ';
59 // A set of characters that, if found in a national prefix formatting rules, are
60 // an indicator to us that we should separate the national prefix from the
61 // number when formatting.
62 const char kNationalPrefixSeparatorsPattern[] = "[- ]";
64 // Replaces any standalone digit in the pattern (not any inside a {} grouping)
65 // with \d. This function replaces the standalone digit regex used in the Java
66 // version which is currently not supported by RE2 because it uses a special
68 void ReplacePatternDigits(string* pattern) {
72 for (string::const_iterator it = pattern->begin(); it != pattern->end();
74 const char current_char = *it;
76 if (isdigit(current_char)) {
77 if (it + 1 != pattern->end()) {
78 const char next_char = it[1];
80 if (next_char != ',' && next_char != '}') {
83 new_pattern += current_char;
89 new_pattern += current_char;
92 pattern->assign(new_pattern);
95 // Matches all the groups contained in 'input' against 'pattern'.
96 void MatchAllGroups(const string& pattern,
98 const AbstractRegExpFactory& regexp_factory,
103 string new_pattern(pattern);
105 // Transforms pattern "(...)(...)(...)" to "(.........)".
106 strrmm(&new_pattern, "()");
107 new_pattern = StrCat("(", new_pattern, ")");
109 const scoped_ptr<RegExpInput> consume_input(
110 regexp_factory.CreateInput(input));
112 cache->GetRegExp(new_pattern).Consume(consume_input.get(), group);
116 PhoneMetadata CreateEmptyMetadata() {
117 PhoneMetadata metadata;
118 metadata.set_international_prefix("NA");
124 AsYouTypeFormatter::AsYouTypeFormatter(const string& region_code)
125 : regexp_factory_(new RegExpFactory()),
126 regexp_cache_(*regexp_factory_.get(), 64),
128 formatting_template_(),
129 current_formatting_pattern_(),
131 accrued_input_without_formatting_(),
132 able_to_format_(true),
133 input_has_formatting_(false),
134 is_complete_number_(false),
135 is_expecting_country_code_(false),
136 phone_util_(*PhoneNumberUtil::GetInstance()),
137 default_country_(region_code),
138 empty_metadata_(CreateEmptyMetadata()),
139 default_metadata_(GetMetadataForRegion(region_code)),
140 current_metadata_(default_metadata_),
141 last_match_position_(0),
142 original_position_(0),
143 position_to_remember_(0),
144 prefix_before_national_number_(),
145 should_add_space_after_national_prefix_(false),
146 national_prefix_extracted_(),
148 possible_formats_() {
151 // The metadata needed by this class is the same for all regions sharing the
152 // same country calling code. Therefore, we return the metadata for "main"
153 // region for this country calling code.
154 const PhoneMetadata* AsYouTypeFormatter::GetMetadataForRegion(
155 const string& region_code) const {
156 int country_calling_code = phone_util_.GetCountryCodeForRegion(region_code);
158 phone_util_.GetRegionCodeForCountryCode(country_calling_code, &main_country);
159 const PhoneMetadata* const metadata =
160 phone_util_.GetMetadataForRegion(main_country);
164 // Set to a default instance of the metadata. This allows us to function with
165 // an incorrect region code, even if formatting only works for numbers
166 // specified with "+".
167 return &empty_metadata_;
170 bool AsYouTypeFormatter::MaybeCreateNewTemplate() {
171 // When there are multiple available formats, the formatter uses the first
172 // format where a formatting template could be created.
173 for (list<const NumberFormat*>::const_iterator it = possible_formats_.begin();
174 it != possible_formats_.end(); ++it) {
176 const NumberFormat& number_format = **it;
177 const string& pattern = number_format.pattern();
178 if (current_formatting_pattern_ == pattern) {
181 if (CreateFormattingTemplate(number_format)) {
182 current_formatting_pattern_ = pattern;
183 SetShouldAddSpaceAfterNationalPrefix(number_format);
184 // With a new formatting template, the matched position using the old
185 // template needs to be reset.
186 last_match_position_ = 0;
190 able_to_format_ = false;
194 void AsYouTypeFormatter::GetAvailableFormats(
195 const string& leading_three_digits) {
196 const RepeatedPtrField<NumberFormat>& format_list =
197 (is_complete_number_ &&
198 current_metadata_->intl_number_format().size() > 0)
199 ? current_metadata_->intl_number_format()
200 : current_metadata_->number_format();
201 bool national_prefix_used_by_country =
202 current_metadata_->has_national_prefix();
203 for (RepeatedPtrField<NumberFormat>::const_iterator it = format_list.begin();
204 it != format_list.end(); ++it) {
205 if (!national_prefix_used_by_country || is_complete_number_ ||
206 it->national_prefix_optional_when_formatting() ||
207 phone_util_.FormattingRuleHasFirstGroupOnly(
208 it->national_prefix_formatting_rule())) {
209 if (phone_util_.IsFormatEligibleForAsYouTypeFormatter(it->format())) {
210 possible_formats_.push_back(&*it);
214 NarrowDownPossibleFormats(leading_three_digits);
217 void AsYouTypeFormatter::NarrowDownPossibleFormats(
218 const string& leading_digits) {
219 const int index_of_leading_digits_pattern =
220 leading_digits.length() - kMinLeadingDigitsLength;
222 for (list<const NumberFormat*>::iterator it = possible_formats_.begin();
223 it != possible_formats_.end(); ) {
225 const NumberFormat& format = **it;
227 if (format.leading_digits_pattern_size() >
228 index_of_leading_digits_pattern) {
229 const scoped_ptr<RegExpInput> input(
230 regexp_factory_->CreateInput(leading_digits));
231 if (!regexp_cache_.GetRegExp(format.leading_digits_pattern().Get(
232 index_of_leading_digits_pattern)).Consume(input.get())) {
233 it = possible_formats_.erase(it);
236 } // else the particular format has no more specific leadingDigitsPattern,
237 // and it should be retained.
242 void AsYouTypeFormatter::SetShouldAddSpaceAfterNationalPrefix(
243 const NumberFormat& format) {
244 static const scoped_ptr<const RegExp> national_prefix_separators_pattern(
245 regexp_factory_->CreateRegExp(kNationalPrefixSeparatorsPattern));
246 should_add_space_after_national_prefix_ =
247 national_prefix_separators_pattern->PartialMatch(
248 format.national_prefix_formatting_rule());
251 bool AsYouTypeFormatter::CreateFormattingTemplate(const NumberFormat& format) {
252 string number_pattern = format.pattern();
254 // The formatter doesn't format numbers when numberPattern contains "|", e.g.
255 // (20|3)\d{4}. In those cases we quickly return.
256 if (number_pattern.find('|') != string::npos) {
259 // Replace anything in the form of [..] with \d.
260 static const scoped_ptr<const RegExp> character_class_pattern(
261 regexp_factory_->CreateRegExp(kCharacterClassPattern));
262 character_class_pattern->GlobalReplace(&number_pattern, "\\\\d");
264 // Replace any standalone digit (not the one in d{}) with \d.
265 ReplacePatternDigits(&number_pattern);
267 string number_format = format.format();
268 formatting_template_.remove();
269 UnicodeString temp_template;
270 GetFormattingTemplate(number_pattern, number_format, &temp_template);
272 if (temp_template.length() > 0) {
273 formatting_template_.append(temp_template);
279 void AsYouTypeFormatter::GetFormattingTemplate(
280 const string& number_pattern,
281 const string& number_format,
282 UnicodeString* formatting_template) {
283 DCHECK(formatting_template);
285 // Creates a phone number consisting only of the digit 9 that matches the
286 // number_pattern by applying the pattern to the longest_phone_number string.
287 static const char longest_phone_number[] = "999999999999999";
288 string a_phone_number;
290 MatchAllGroups(number_pattern, longest_phone_number, *regexp_factory_,
291 ®exp_cache_, &a_phone_number);
292 // No formatting template can be created if the number of digits entered so
293 // far is longer than the maximum the current formatting rule can accommodate.
294 if (a_phone_number.length() < national_number_.length()) {
295 formatting_template->remove();
298 // Formats the number according to number_format.
299 regexp_cache_.GetRegExp(number_pattern).GlobalReplace(
300 &a_phone_number, number_format);
301 // Replaces each digit with character kDigitPlaceholder.
302 GlobalReplaceSubstring("9", kDigitPlaceholder, &a_phone_number);
303 formatting_template->setTo(a_phone_number.c_str(), a_phone_number.size());
306 void AsYouTypeFormatter::Clear() {
307 current_output_.clear();
308 accrued_input_.remove();
309 accrued_input_without_formatting_.remove();
310 formatting_template_.remove();
311 last_match_position_ = 0;
312 current_formatting_pattern_.clear();
313 prefix_before_national_number_.clear();
314 national_prefix_extracted_.clear();
315 national_number_.clear();
316 able_to_format_ = true;
317 input_has_formatting_ = false;
318 position_to_remember_ = 0;
319 original_position_ = 0;
320 is_complete_number_ = false;
321 is_expecting_country_code_ = false;
322 possible_formats_.clear();
323 should_add_space_after_national_prefix_ = false;
325 if (current_metadata_ != default_metadata_) {
326 current_metadata_ = GetMetadataForRegion(default_country_);
330 const string& AsYouTypeFormatter::InputDigit(char32 next_char, string* result) {
333 InputDigitWithOptionToRememberPosition(next_char, false, ¤t_output_);
334 result->assign(current_output_);
338 const string& AsYouTypeFormatter::InputDigitAndRememberPosition(
343 InputDigitWithOptionToRememberPosition(next_char, true, ¤t_output_);
344 result->assign(current_output_);
348 void AsYouTypeFormatter::InputDigitWithOptionToRememberPosition(
350 bool remember_position,
351 string* phone_number) {
352 DCHECK(phone_number);
354 accrued_input_.append(next_char);
355 if (remember_position) {
356 original_position_ = accrued_input_.length();
358 // We do formatting on-the-fly only when each character entered is either a
359 // plus sign (accepted at the start of the number only).
360 string next_char_string;
361 UnicodeString(next_char).toUTF8String(next_char_string);
363 char normalized_next_char = '\0';
364 if (!(phone_util_.ContainsOnlyValidDigits(next_char_string) ||
365 (accrued_input_.length() == 1 && next_char == kPlusSign))) {
366 able_to_format_ = false;
367 input_has_formatting_ = true;
369 normalized_next_char =
370 NormalizeAndAccrueDigitsAndPlusSign(next_char, remember_position);
372 if (!able_to_format_) {
373 // When we are unable to format because of reasons other than that
374 // formatting chars have been entered, it can be due to really long IDDs or
375 // NDDs. If that is the case, we might be able to do formatting again after
377 if (input_has_formatting_) {
378 phone_number->clear();
379 accrued_input_.toUTF8String(*phone_number);
380 } else if (AttemptToExtractIdd()) {
381 if (AttemptToExtractCountryCode()) {
382 AttemptToChoosePatternWithPrefixExtracted(phone_number);
385 } else if (AbleToExtractLongerNdd()) {
386 // Add an additional space to separate long NDD and national significant
387 // number for readability. We don't set
388 // should_add_space_after_national_prefix_ to true, since we don't want
389 // this to change later when we choose formatting templates.
390 prefix_before_national_number_.push_back(kSeparatorBeforeNationalNumber);
391 AttemptToChoosePatternWithPrefixExtracted(phone_number);
394 phone_number->clear();
395 accrued_input_.toUTF8String(*phone_number);
399 // We start to attempt to format only when at least kMinLeadingDigitsLength
400 // digits (the plus sign is counted as a digit as well for this purpose) have
402 switch (accrued_input_without_formatting_.length()) {
406 phone_number->clear();
407 accrued_input_.toUTF8String(*phone_number);
410 if (AttemptToExtractIdd()) {
411 is_expecting_country_code_ = true;
413 // No IDD or plus sign is found, might be entering in national format.
414 RemoveNationalPrefixFromNationalNumber(&national_prefix_extracted_);
415 AttemptToChooseFormattingPattern(phone_number);
419 if (is_expecting_country_code_) {
420 if (AttemptToExtractCountryCode()) {
421 is_expecting_country_code_ = false;
423 phone_number->assign(prefix_before_national_number_);
424 phone_number->append(national_number_);
427 if (possible_formats_.size() > 0) {
428 // The formatting pattern is already chosen.
429 string temp_national_number;
430 InputDigitHelper(normalized_next_char, &temp_national_number);
431 // See if accrued digits can be formatted properly already. If not, use
432 // the results from InputDigitHelper, which does formatting based on the
433 // formatting pattern chosen.
434 string formatted_number;
435 AttemptToFormatAccruedDigits(&formatted_number);
436 if (formatted_number.length() > 0) {
437 phone_number->assign(formatted_number);
440 NarrowDownPossibleFormats(national_number_);
441 if (MaybeCreateNewTemplate()) {
442 InputAccruedNationalNumber(phone_number);
445 if (able_to_format_) {
446 AppendNationalNumber(temp_national_number, phone_number);
448 phone_number->clear();
449 accrued_input_.toUTF8String(*phone_number);
453 AttemptToChooseFormattingPattern(phone_number);
458 void AsYouTypeFormatter::AttemptToChoosePatternWithPrefixExtracted(
459 string* formatted_number) {
460 able_to_format_ = true;
461 is_expecting_country_code_ = false;
462 possible_formats_.clear();
463 AttemptToChooseFormattingPattern(formatted_number);
466 bool AsYouTypeFormatter::AbleToExtractLongerNdd() {
467 if (national_prefix_extracted_.length() > 0) {
468 // Put the extracted NDD back to the national number before attempting to
469 // extract a new NDD.
470 national_number_.insert(0, national_prefix_extracted_);
471 // Remove the previously extracted NDD from prefixBeforeNationalNumber. We
472 // cannot simply set it to empty string because people sometimes enter
473 // national prefix after country code, e.g +44 (0)20-1234-5678.
474 int index_of_previous_ndd =
475 prefix_before_national_number_.find_last_of(national_prefix_extracted_);
476 prefix_before_national_number_.resize(index_of_previous_ndd);
478 string new_national_prefix;
479 RemoveNationalPrefixFromNationalNumber(&new_national_prefix);
480 return national_prefix_extracted_ != new_national_prefix;
483 void AsYouTypeFormatter::AttemptToFormatAccruedDigits(
484 string* formatted_result) {
485 DCHECK(formatted_result);
487 for (list<const NumberFormat*>::const_iterator it = possible_formats_.begin();
488 it != possible_formats_.end(); ++it) {
490 const NumberFormat& number_format = **it;
491 const string& pattern = number_format.pattern();
493 if (regexp_cache_.GetRegExp(pattern).FullMatch(national_number_)) {
494 SetShouldAddSpaceAfterNationalPrefix(number_format);
496 string formatted_number(national_number_);
497 bool status = regexp_cache_.GetRegExp(pattern).GlobalReplace(
498 &formatted_number, number_format.format());
501 AppendNationalNumber(formatted_number, formatted_result);
507 int AsYouTypeFormatter::GetRememberedPosition() const {
508 UnicodeString current_output(current_output_.c_str());
509 if (!able_to_format_) {
510 return ConvertUnicodeStringPosition(current_output, original_position_);
512 int accrued_input_index = 0;
513 int current_output_index = 0;
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;
521 ++current_output_index;
523 return ConvertUnicodeStringPosition(current_output, current_output_index);
526 void AsYouTypeFormatter::AppendNationalNumber(const string& national_number,
527 string* phone_number) const {
528 int prefix_before_national_number_length =
529 prefix_before_national_number_.size();
530 if (should_add_space_after_national_prefix_ &&
531 prefix_before_national_number_length > 0 &&
532 prefix_before_national_number_.at(
533 prefix_before_national_number_length - 1) !=
534 kSeparatorBeforeNationalNumber) {
535 // We want to add a space after the national prefix if the national prefix
536 // formatting rule indicates that this would normally be done, with the
537 // exception of the case where we already appended a space because the NDD
538 // was surprisingly long.
539 phone_number->assign(prefix_before_national_number_);
540 phone_number->push_back(kSeparatorBeforeNationalNumber);
541 StrAppend(phone_number, national_number);
543 phone_number->assign(
544 StrCat(prefix_before_national_number_, national_number));
548 void AsYouTypeFormatter::AttemptToChooseFormattingPattern(
549 string* formatted_number) {
550 DCHECK(formatted_number);
552 if (national_number_.length() >= kMinLeadingDigitsLength) {
553 const string leading_digits =
554 national_number_.substr(0, kMinLeadingDigitsLength);
556 GetAvailableFormats(leading_digits);
557 if (MaybeCreateNewTemplate()) {
558 InputAccruedNationalNumber(formatted_number);
560 formatted_number->clear();
561 accrued_input_.toUTF8String(*formatted_number);
565 AppendNationalNumber(national_number_, formatted_number);
569 void AsYouTypeFormatter::InputAccruedNationalNumber(string* number) {
571 int length_of_national_number = national_number_.length();
573 if (length_of_national_number > 0) {
574 string temp_national_number;
576 for (int i = 0; i < length_of_national_number; ++i) {
577 temp_national_number.clear();
578 InputDigitHelper(national_number_[i], &temp_national_number);
580 if (able_to_format_) {
581 AppendNationalNumber(temp_national_number, number);
584 accrued_input_.toUTF8String(*number);
588 number->assign(prefix_before_national_number_);
592 bool AsYouTypeFormatter::IsNanpaNumberWithNationalPrefix() const {
593 // For NANPA numbers beginning with 1[2-9], treat the 1 as the national
594 // prefix. The reason is that national significant numbers in NANPA always
595 // start with [2-9] after the national prefix. Numbers beginning with 1[01]
596 // can only be short/emergency numbers, which don't need the national
598 return (current_metadata_->country_code() == 1) &&
599 (national_number_[0] == '1') && (national_number_[1] != '0') &&
600 (national_number_[1] != '1');
603 void AsYouTypeFormatter::RemoveNationalPrefixFromNationalNumber(
604 string* national_prefix) {
605 int start_of_national_number = 0;
607 if (IsNanpaNumberWithNationalPrefix()) {
608 start_of_national_number = 1;
609 prefix_before_national_number_.append("1");
610 prefix_before_national_number_.push_back(kSeparatorBeforeNationalNumber);
611 is_complete_number_ = true;
612 } else if (current_metadata_->has_national_prefix_for_parsing()) {
613 const scoped_ptr<RegExpInput> consumed_input(
614 regexp_factory_->CreateInput(national_number_));
615 const RegExp& pattern = regexp_cache_.GetRegExp(
616 current_metadata_->national_prefix_for_parsing());
618 if (pattern.Consume(consumed_input.get())) {
619 // When the national prefix is detected, we use international formatting
620 // rules instead of national ones, because national formatting rules could
621 // countain local formatting rules for numbers entered without area code.
622 is_complete_number_ = true;
623 start_of_national_number =
624 national_number_.length() - consumed_input->ToString().length();
625 prefix_before_national_number_.append(
626 national_number_.substr(0, start_of_national_number));
629 national_prefix->assign(national_number_, 0, start_of_national_number);
630 national_number_.erase(0, start_of_national_number);
633 bool AsYouTypeFormatter::AttemptToExtractIdd() {
634 string accrued_input_without_formatting_stdstring;
635 accrued_input_without_formatting_
636 .toUTF8String(accrued_input_without_formatting_stdstring);
637 const scoped_ptr<RegExpInput> consumed_input(
638 regexp_factory_->CreateInput(accrued_input_without_formatting_stdstring));
639 const RegExp& international_prefix = regexp_cache_.GetRegExp(
640 StrCat("\\", string(&kPlusSign, 1), "|",
641 current_metadata_->international_prefix()));
643 if (international_prefix.Consume(consumed_input.get())) {
644 is_complete_number_ = true;
645 const int start_of_country_code =
646 accrued_input_without_formatting_.length() -
647 consumed_input->ToString().length();
649 national_number_.clear();
650 accrued_input_without_formatting_.tempSubString(start_of_country_code)
651 .toUTF8String(national_number_);
653 string before_country_code;
654 accrued_input_without_formatting_.tempSubString(0, start_of_country_code)
655 .toUTF8String(before_country_code);
656 prefix_before_national_number_.clear();
657 prefix_before_national_number_.append(before_country_code);
659 if (accrued_input_without_formatting_[0] != kPlusSign) {
660 prefix_before_national_number_.push_back(kSeparatorBeforeNationalNumber);
667 bool AsYouTypeFormatter::AttemptToExtractCountryCode() {
668 if (national_number_.length() == 0) {
671 string number_without_country_code(national_number_);
673 phone_util_.ExtractCountryCode(&number_without_country_code);
674 if (country_code == 0) {
677 national_number_.assign(number_without_country_code);
678 string new_region_code;
679 phone_util_.GetRegionCodeForCountryCode(country_code, &new_region_code);
680 if (PhoneNumberUtil::kRegionCodeForNonGeoEntity == new_region_code) {
682 phone_util_.GetMetadataForNonGeographicalRegion(country_code);
683 } else if (new_region_code != default_country_) {
684 current_metadata_ = GetMetadataForRegion(new_region_code);
686 StrAppend(&prefix_before_national_number_, country_code);
687 prefix_before_national_number_.push_back(kSeparatorBeforeNationalNumber);
692 char AsYouTypeFormatter::NormalizeAndAccrueDigitsAndPlusSign(
694 bool remember_position) {
695 char normalized_char = next_char;
697 if (next_char == kPlusSign) {
698 accrued_input_without_formatting_.append(next_char);
701 UnicodeString(next_char).toUTF8String(number);
702 phone_util_.NormalizeDigitsOnly(&number);
703 accrued_input_without_formatting_.append(next_char);
704 national_number_.append(number);
705 normalized_char = number[0];
707 if (remember_position) {
708 position_to_remember_ = accrued_input_without_formatting_.length();
710 return normalized_char;
713 void AsYouTypeFormatter::InputDigitHelper(char next_char, string* number) {
716 const char32 placeholder_codepoint = UnicodeString(kDigitPlaceholder)[0];
717 int placeholder_pos = formatting_template_
718 .tempSubString(last_match_position_).indexOf(placeholder_codepoint);
719 if (placeholder_pos != -1) {
720 UnicodeString temp_template = formatting_template_;
721 placeholder_pos = temp_template.indexOf(placeholder_codepoint);
722 temp_template.setCharAt(placeholder_pos, UnicodeString(next_char)[0]);
723 last_match_position_ = placeholder_pos;
724 formatting_template_.replace(0, temp_template.length(), temp_template);
725 formatting_template_.tempSubString(0, last_match_position_ + 1)
726 .toUTF8String(*number);
728 if (possible_formats_.size() == 1) {
729 // More digits are entered than we could handle, and there are no other
730 // valid patterns to try.
731 able_to_format_ = false;
732 } // else, we just reset the formatting pattern.
733 current_formatting_pattern_.clear();
734 accrued_input_.toUTF8String(*number);
738 // Returns the number of bytes contained in the given UnicodeString up to the
739 // specified position.
741 int AsYouTypeFormatter::ConvertUnicodeStringPosition(const UnicodeString& s,
743 if (pos > s.length()) {
747 s.tempSubString(0, pos).toUTF8String(substring);
748 return substring.length();
751 } // namespace phonenumbers