blob: 9095a560046ef15dd07aef225cd8f54bc11ee292 [file] [log] [blame]
// Copyright (C) 2011 The Libphonenumber Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "phonenumbers/asyoutypeformatter.h"
#include <cctype>
#include <list>
#include <string>
#include <google/protobuf/message_lite.h>
#include "phonenumbers/base/logging.h"
#include "phonenumbers/base/memory/scoped_ptr.h"
#include "phonenumbers/phonemetadata.pb.h"
#include "phonenumbers/phonenumberutil.h"
#include "phonenumbers/regexp_cache.h"
#include "phonenumbers/regexp_factory.h"
#include "phonenumbers/stringutil.h"
#include "phonenumbers/unicodestring.h"
namespace i18n {
namespace phonenumbers {
using google::protobuf::RepeatedPtrField;
namespace {
const char kPlusSign = '+';
// A pattern that is used to match character classes in regular expressions.
// An example of a character class is [1-4].
const char kCharacterClassPattern[] = "\\[([^\\[\\]])*\\]";
// This is the minimum length of national number accrued that is required to
// trigger the formatter. The first element of the leading_digits_pattern of
// each number_format contains a regular expression that matches up to this
// number of digits.
const size_t kMinLeadingDigitsLength = 3;
// The digits that have not been entered yet will be represented by a \u2008,
// the punctuation space.
const char kDigitPlaceholder[] = "\xE2\x80\x88"; /* " " */
// Character used when appropriate to separate a prefix, such as a long NDD or a
// country calling code, from the national number.
const char kSeparatorBeforeNationalNumber = ' ';
// A set of characters that, if found in a national prefix formatting rules, are
// an indicator to us that we should separate the national prefix from the
// number when formatting.
const char kNationalPrefixSeparatorsPattern[] = "[- ]";
// Replaces any standalone digit in the pattern (not any inside a {} grouping)
// with \d. This function replaces the standalone digit regex used in the Java
// version which is currently not supported by RE2 because it uses a special
// construct (?=).
void ReplacePatternDigits(string* pattern) {
DCHECK(pattern);
string new_pattern;
// This is needed since sometimes there is more than one digit in between the
// curly braces.
bool is_in_braces = false;
for (string::const_iterator it = pattern->begin(); it != pattern->end();
++it) {
const char current_char = *it;
if (isdigit(current_char)) {
if (is_in_braces) {
new_pattern += current_char;
} else {
new_pattern += "\\d";
}
} else {
new_pattern += current_char;
if (current_char == '{') {
is_in_braces = true;
} else if (current_char == '}') {
is_in_braces = false;
}
}
}
pattern->assign(new_pattern);
}
// Matches all the groups contained in 'input' against 'pattern'.
void MatchAllGroups(const string& pattern,
const string& input,
const AbstractRegExpFactory& regexp_factory,
RegExpCache* cache,
string* group) {
DCHECK(cache);
DCHECK(group);
string new_pattern(pattern);
// Transforms pattern "(...)(...)(...)" to "(.........)".
strrmm(&new_pattern, "()");
new_pattern = StrCat("(", new_pattern, ")");
const scoped_ptr<RegExpInput> consume_input(
regexp_factory.CreateInput(input));
bool status =
cache->GetRegExp(new_pattern).Consume(consume_input.get(), group);
DCHECK(status);
}
PhoneMetadata CreateEmptyMetadata() {
PhoneMetadata metadata;
metadata.set_international_prefix("NA");
return metadata;
}
} // namespace
AsYouTypeFormatter::AsYouTypeFormatter(const string& region_code)
: regexp_factory_(new RegExpFactory()),
regexp_cache_(*regexp_factory_.get(), 64),
current_output_(),
formatting_template_(),
current_formatting_pattern_(),
accrued_input_(),
accrued_input_without_formatting_(),
able_to_format_(true),
input_has_formatting_(false),
is_complete_number_(false),
is_expecting_country_code_(false),
phone_util_(*PhoneNumberUtil::GetInstance()),
default_country_(region_code),
empty_metadata_(CreateEmptyMetadata()),
default_metadata_(GetMetadataForRegion(region_code)),
current_metadata_(default_metadata_),
last_match_position_(0),
original_position_(0),
position_to_remember_(0),
prefix_before_national_number_(),
should_add_space_after_national_prefix_(false),
national_prefix_extracted_(),
national_number_(),
possible_formats_() {
}
// The metadata needed by this class is the same for all regions sharing the
// same country calling code. Therefore, we return the metadata for "main"
// region for this country calling code.
const PhoneMetadata* AsYouTypeFormatter::GetMetadataForRegion(
const string& region_code) const {
int country_calling_code = phone_util_.GetCountryCodeForRegion(region_code);
string main_country;
phone_util_.GetRegionCodeForCountryCode(country_calling_code, &main_country);
const PhoneMetadata* const metadata =
phone_util_.GetMetadataForRegion(main_country);
if (metadata) {
return metadata;
}
// Set to a default instance of the metadata. This allows us to function with
// an incorrect region code, even if formatting only works for numbers
// specified with "+".
return &empty_metadata_;
}
bool AsYouTypeFormatter::MaybeCreateNewTemplate() {
// When there are multiple available formats, the formatter uses the first
// format where a formatting template could be created.
for (list<const NumberFormat*>::const_iterator it = possible_formats_.begin();
it != possible_formats_.end(); ++it) {
DCHECK(*it);
const NumberFormat& number_format = **it;
const string& pattern = number_format.pattern();
if (current_formatting_pattern_ == pattern) {
return false;
}
if (CreateFormattingTemplate(number_format)) {
current_formatting_pattern_ = pattern;
SetShouldAddSpaceAfterNationalPrefix(number_format);
// With a new formatting template, the matched position using the old
// template needs to be reset.
last_match_position_ = 0;
return true;
}
}
able_to_format_ = false;
return false;
}
void AsYouTypeFormatter::GetAvailableFormats(
const string& leading_three_digits) {
const RepeatedPtrField<NumberFormat>& format_list =
(is_complete_number_ &&
current_metadata_->intl_number_format().size() > 0)
? current_metadata_->intl_number_format()
: current_metadata_->number_format();
bool national_prefix_used_by_country =
current_metadata_->has_national_prefix();
for (RepeatedPtrField<NumberFormat>::const_iterator it = format_list.begin();
it != format_list.end(); ++it) {
if (!national_prefix_used_by_country || is_complete_number_ ||
it->national_prefix_optional_when_formatting() ||
phone_util_.FormattingRuleHasFirstGroupOnly(
it->national_prefix_formatting_rule())) {
if (phone_util_.IsFormatEligibleForAsYouTypeFormatter(it->format())) {
possible_formats_.push_back(&*it);
}
}
}
NarrowDownPossibleFormats(leading_three_digits);
}
void AsYouTypeFormatter::NarrowDownPossibleFormats(
const string& leading_digits) {
const int index_of_leading_digits_pattern =
leading_digits.length() - kMinLeadingDigitsLength;
for (list<const NumberFormat*>::iterator it = possible_formats_.begin();
it != possible_formats_.end(); ) {
DCHECK(*it);
const NumberFormat& format = **it;
if (format.leading_digits_pattern_size() >
index_of_leading_digits_pattern) {
const scoped_ptr<RegExpInput> input(
regexp_factory_->CreateInput(leading_digits));
if (!regexp_cache_.GetRegExp(format.leading_digits_pattern().Get(
index_of_leading_digits_pattern)).Consume(input.get())) {
it = possible_formats_.erase(it);
continue;
}
} // else the particular format has no more specific leadingDigitsPattern,
// and it should be retained.
++it;
}
}
void AsYouTypeFormatter::SetShouldAddSpaceAfterNationalPrefix(
const NumberFormat& format) {
static const scoped_ptr<const RegExp> national_prefix_separators_pattern(
regexp_factory_->CreateRegExp(kNationalPrefixSeparatorsPattern));
should_add_space_after_national_prefix_ =
national_prefix_separators_pattern->PartialMatch(
format.national_prefix_formatting_rule());
}
bool AsYouTypeFormatter::CreateFormattingTemplate(const NumberFormat& format) {
string number_pattern = format.pattern();
// The formatter doesn't format numbers when numberPattern contains "|", e.g.
// (20|3)\d{4}. In those cases we quickly return.
if (number_pattern.find('|') != string::npos) {
return false;
}
// Replace anything in the form of [..] with \d.
static const scoped_ptr<const RegExp> character_class_pattern(
regexp_factory_->CreateRegExp(kCharacterClassPattern));
character_class_pattern->GlobalReplace(&number_pattern, "\\\\d");
// Replace any standalone digit (not the one in d{}) with \d.
ReplacePatternDigits(&number_pattern);
string number_format = format.format();
formatting_template_.remove();
UnicodeString temp_template;
GetFormattingTemplate(number_pattern, number_format, &temp_template);
if (temp_template.length() > 0) {
formatting_template_.append(temp_template);
return true;
}
return false;
}
void AsYouTypeFormatter::GetFormattingTemplate(
const string& number_pattern,
const string& number_format,
UnicodeString* formatting_template) {
DCHECK(formatting_template);
// Creates a phone number consisting only of the digit 9 that matches the
// number_pattern by applying the pattern to the longest_phone_number string.
static const char longest_phone_number[] = "999999999999999";
string a_phone_number;
MatchAllGroups(number_pattern, longest_phone_number, *regexp_factory_,
&regexp_cache_, &a_phone_number);
// No formatting template can be created if the number of digits entered so
// far is longer than the maximum the current formatting rule can accommodate.
if (a_phone_number.length() < national_number_.length()) {
formatting_template->remove();
return;
}
// Formats the number according to number_format.
regexp_cache_.GetRegExp(number_pattern).GlobalReplace(
&a_phone_number, number_format);
// Replaces each digit with character kDigitPlaceholder.
GlobalReplaceSubstring("9", kDigitPlaceholder, &a_phone_number);
formatting_template->setTo(a_phone_number.c_str(), a_phone_number.size());
}
void AsYouTypeFormatter::Clear() {
current_output_.clear();
accrued_input_.remove();
accrued_input_without_formatting_.remove();
formatting_template_.remove();
last_match_position_ = 0;
current_formatting_pattern_.clear();
prefix_before_national_number_.clear();
national_prefix_extracted_.clear();
national_number_.clear();
able_to_format_ = true;
input_has_formatting_ = false;
position_to_remember_ = 0;
original_position_ = 0;
is_complete_number_ = false;
is_expecting_country_code_ = false;
possible_formats_.clear();
should_add_space_after_national_prefix_ = false;
if (current_metadata_ != default_metadata_) {
current_metadata_ = GetMetadataForRegion(default_country_);
}
}
const string& AsYouTypeFormatter::InputDigit(char32 next_char, string* result) {
DCHECK(result);
InputDigitWithOptionToRememberPosition(next_char, false, &current_output_);
result->assign(current_output_);
return *result;
}
const string& AsYouTypeFormatter::InputDigitAndRememberPosition(
char32 next_char,
string* result) {
DCHECK(result);
InputDigitWithOptionToRememberPosition(next_char, true, &current_output_);
result->assign(current_output_);
return *result;
}
void AsYouTypeFormatter::InputDigitWithOptionToRememberPosition(
char32 next_char,
bool remember_position,
string* phone_number) {
DCHECK(phone_number);
accrued_input_.append(next_char);
if (remember_position) {
original_position_ = accrued_input_.length();
}
// We do formatting on-the-fly only when each character entered is either a
// plus sign (accepted at the start of the number only).
string next_char_string;
UnicodeString(next_char).toUTF8String(next_char_string);
char normalized_next_char = '\0';
if (!(phone_util_.ContainsOnlyValidDigits(next_char_string) ||
(accrued_input_.length() == 1 && next_char == kPlusSign))) {
able_to_format_ = false;
input_has_formatting_ = true;
} else {
normalized_next_char =
NormalizeAndAccrueDigitsAndPlusSign(next_char, remember_position);
}
if (!able_to_format_) {
// When we are unable to format because of reasons other than that
// formatting chars have been entered, it can be due to really long IDDs or
// NDDs. If that is the case, we might be able to do formatting again after
// extracting them.
if (input_has_formatting_) {
phone_number->clear();
accrued_input_.toUTF8String(*phone_number);
} else if (AttemptToExtractIdd()) {
if (AttemptToExtractCountryCode()) {
AttemptToChoosePatternWithPrefixExtracted(phone_number);
return;
}
} else if (AbleToExtractLongerNdd()) {
// Add an additional space to separate long NDD and national significant
// number for readability. We don't set
// should_add_space_after_national_prefix_ to true, since we don't want
// this to change later when we choose formatting templates.
prefix_before_national_number_.push_back(kSeparatorBeforeNationalNumber);
AttemptToChoosePatternWithPrefixExtracted(phone_number);
return;
}
phone_number->clear();
accrued_input_.toUTF8String(*phone_number);
return;
}
// We start to attempt to format only when at least kMinLeadingDigitsLength
// digits (the plus sign is counted as a digit as well for this purpose) have
// been entered.
switch (accrued_input_without_formatting_.length()) {
case 0:
case 1:
case 2:
phone_number->clear();
accrued_input_.toUTF8String(*phone_number);
return;
case 3:
if (AttemptToExtractIdd()) {
is_expecting_country_code_ = true;
} else {
// No IDD or plus sign is found, might be entering in national format.
RemoveNationalPrefixFromNationalNumber(&national_prefix_extracted_);
AttemptToChooseFormattingPattern(phone_number);
return;
}
default:
if (is_expecting_country_code_) {
if (AttemptToExtractCountryCode()) {
is_expecting_country_code_ = false;
}
phone_number->assign(prefix_before_national_number_);
phone_number->append(national_number_);
return;
}
if (possible_formats_.size() > 0) {
// The formatting pattern is already chosen.
string temp_national_number;
InputDigitHelper(normalized_next_char, &temp_national_number);
// See if accrued digits can be formatted properly already. If not, use
// the results from InputDigitHelper, which does formatting based on the
// formatting pattern chosen.
string formatted_number;
AttemptToFormatAccruedDigits(&formatted_number);
if (formatted_number.length() > 0) {
phone_number->assign(formatted_number);
return;
}
NarrowDownPossibleFormats(national_number_);
if (MaybeCreateNewTemplate()) {
InputAccruedNationalNumber(phone_number);
return;
}
if (able_to_format_) {
AppendNationalNumber(temp_national_number, phone_number);
} else {
phone_number->clear();
accrued_input_.toUTF8String(*phone_number);
}
return;
} else {
AttemptToChooseFormattingPattern(phone_number);
}
}
}
void AsYouTypeFormatter::AttemptToChoosePatternWithPrefixExtracted(
string* formatted_number) {
able_to_format_ = true;
is_expecting_country_code_ = false;
possible_formats_.clear();
AttemptToChooseFormattingPattern(formatted_number);
}
bool AsYouTypeFormatter::AbleToExtractLongerNdd() {
if (national_prefix_extracted_.length() > 0) {
// Put the extracted NDD back to the national number before attempting to
// extract a new NDD.
national_number_.insert(0, national_prefix_extracted_);
// Remove the previously extracted NDD from prefixBeforeNationalNumber. We
// cannot simply set it to empty string because people sometimes incorrectly
// enter national prefix after the country code, e.g. +44 (0)20-1234-5678.
int index_of_previous_ndd =
prefix_before_national_number_.find_last_of(national_prefix_extracted_);
prefix_before_national_number_.resize(index_of_previous_ndd);
}
string new_national_prefix;
RemoveNationalPrefixFromNationalNumber(&new_national_prefix);
return national_prefix_extracted_ != new_national_prefix;
}
void AsYouTypeFormatter::AttemptToFormatAccruedDigits(
string* formatted_result) {
DCHECK(formatted_result);
for (list<const NumberFormat*>::const_iterator it = possible_formats_.begin();
it != possible_formats_.end(); ++it) {
DCHECK(*it);
const NumberFormat& number_format = **it;
const string& pattern = number_format.pattern();
if (regexp_cache_.GetRegExp(pattern).FullMatch(national_number_)) {
SetShouldAddSpaceAfterNationalPrefix(number_format);
string formatted_number(national_number_);
bool status = regexp_cache_.GetRegExp(pattern).GlobalReplace(
&formatted_number, number_format.format());
DCHECK(status);
AppendNationalNumber(formatted_number, formatted_result);
return;
}
}
}
int AsYouTypeFormatter::GetRememberedPosition() const {
UnicodeString current_output(current_output_.c_str());
if (!able_to_format_) {
return ConvertUnicodeStringPosition(current_output, original_position_);
}
int accrued_input_index = 0;
int current_output_index = 0;
while (accrued_input_index < position_to_remember_ &&
current_output_index < current_output.length()) {
if (accrued_input_without_formatting_[accrued_input_index] ==
current_output[current_output_index]) {
++accrued_input_index;
}
++current_output_index;
}
return ConvertUnicodeStringPosition(current_output, current_output_index);
}
void AsYouTypeFormatter::AppendNationalNumber(const string& national_number,
string* phone_number) const {
int prefix_before_national_number_length =
prefix_before_national_number_.size();
if (should_add_space_after_national_prefix_ &&
prefix_before_national_number_length > 0 &&
prefix_before_national_number_.at(
prefix_before_national_number_length - 1) !=
kSeparatorBeforeNationalNumber) {
// We want to add a space after the national prefix if the national prefix
// formatting rule indicates that this would normally be done, with the
// exception of the case where we already appended a space because the NDD
// was surprisingly long.
phone_number->assign(prefix_before_national_number_);
phone_number->push_back(kSeparatorBeforeNationalNumber);
StrAppend(phone_number, national_number);
} else {
phone_number->assign(
StrCat(prefix_before_national_number_, national_number));
}
}
void AsYouTypeFormatter::AttemptToChooseFormattingPattern(
string* formatted_number) {
DCHECK(formatted_number);
if (national_number_.length() >= kMinLeadingDigitsLength) {
const string leading_digits =
national_number_.substr(0, kMinLeadingDigitsLength);
GetAvailableFormats(leading_digits);
formatted_number->clear();
AttemptToFormatAccruedDigits(formatted_number);
// See if the accrued digits can be formatted properly already.
if (formatted_number->length() > 0) {
return;
}
if (MaybeCreateNewTemplate()) {
InputAccruedNationalNumber(formatted_number);
} else {
formatted_number->clear();
accrued_input_.toUTF8String(*formatted_number);
}
return;
} else {
AppendNationalNumber(national_number_, formatted_number);
}
}
void AsYouTypeFormatter::InputAccruedNationalNumber(string* number) {
DCHECK(number);
int length_of_national_number = national_number_.length();
if (length_of_national_number > 0) {
string temp_national_number;
for (int i = 0; i < length_of_national_number; ++i) {
temp_national_number.clear();
InputDigitHelper(national_number_[i], &temp_national_number);
}
if (able_to_format_) {
AppendNationalNumber(temp_national_number, number);
} else {
number->clear();
accrued_input_.toUTF8String(*number);
}
return;
} else {
number->assign(prefix_before_national_number_);
}
}
bool AsYouTypeFormatter::IsNanpaNumberWithNationalPrefix() const {
// For NANPA numbers beginning with 1[2-9], treat the 1 as the national
// prefix. The reason is that national significant numbers in NANPA always
// start with [2-9] after the national prefix. Numbers beginning with 1[01]
// can only be short/emergency numbers, which don't need the national
// prefix.
return (current_metadata_->country_code() == 1) &&
(national_number_[0] == '1') && (national_number_[1] != '0') &&
(national_number_[1] != '1');
}
void AsYouTypeFormatter::RemoveNationalPrefixFromNationalNumber(
string* national_prefix) {
int start_of_national_number = 0;
if (IsNanpaNumberWithNationalPrefix()) {
start_of_national_number = 1;
prefix_before_national_number_.append("1");
prefix_before_national_number_.push_back(kSeparatorBeforeNationalNumber);
is_complete_number_ = true;
} else if (current_metadata_->has_national_prefix_for_parsing()) {
const scoped_ptr<RegExpInput> consumed_input(
regexp_factory_->CreateInput(national_number_));
const RegExp& pattern = regexp_cache_.GetRegExp(
current_metadata_->national_prefix_for_parsing());
// Since some national prefix patterns are entirely optional, check that a
// national prefix could actually be extracted.
if (pattern.Consume(consumed_input.get())) {
start_of_national_number =
national_number_.length() - consumed_input->ToString().length();
if (start_of_national_number > 0) {
// When the national prefix is detected, we use international formatting
// rules instead of national ones, because national formatting rules
// could countain local formatting rules for numbers entered without
// area code.
is_complete_number_ = true;
prefix_before_national_number_.append(
national_number_.substr(0, start_of_national_number));
}
}
}
national_prefix->assign(national_number_, 0, start_of_national_number);
national_number_.erase(0, start_of_national_number);
}
bool AsYouTypeFormatter::AttemptToExtractIdd() {
string accrued_input_without_formatting_stdstring;
accrued_input_without_formatting_
.toUTF8String(accrued_input_without_formatting_stdstring);
const scoped_ptr<RegExpInput> consumed_input(
regexp_factory_->CreateInput(accrued_input_without_formatting_stdstring));
const RegExp& international_prefix = regexp_cache_.GetRegExp(
StrCat("\\", string(&kPlusSign, 1), "|",
current_metadata_->international_prefix()));
if (international_prefix.Consume(consumed_input.get())) {
is_complete_number_ = true;
const int start_of_country_code =
accrued_input_without_formatting_.length() -
consumed_input->ToString().length();
national_number_.clear();
accrued_input_without_formatting_.tempSubString(start_of_country_code)
.toUTF8String(national_number_);
string before_country_code;
accrued_input_without_formatting_.tempSubString(0, start_of_country_code)
.toUTF8String(before_country_code);
prefix_before_national_number_.clear();
prefix_before_national_number_.append(before_country_code);
if (accrued_input_without_formatting_[0] != kPlusSign) {
prefix_before_national_number_.push_back(kSeparatorBeforeNationalNumber);
}
return true;
}
return false;
}
bool AsYouTypeFormatter::AttemptToExtractCountryCode() {
if (national_number_.length() == 0) {
return false;
}
string number_without_country_code(national_number_);
int country_code =
phone_util_.ExtractCountryCode(&number_without_country_code);
if (country_code == 0) {
return false;
}
national_number_.assign(number_without_country_code);
string new_region_code;
phone_util_.GetRegionCodeForCountryCode(country_code, &new_region_code);
if (PhoneNumberUtil::kRegionCodeForNonGeoEntity == new_region_code) {
current_metadata_ =
phone_util_.GetMetadataForNonGeographicalRegion(country_code);
} else if (new_region_code != default_country_) {
current_metadata_ = GetMetadataForRegion(new_region_code);
}
StrAppend(&prefix_before_national_number_, country_code);
prefix_before_national_number_.push_back(kSeparatorBeforeNationalNumber);
return true;
}
char AsYouTypeFormatter::NormalizeAndAccrueDigitsAndPlusSign(
char32 next_char,
bool remember_position) {
char normalized_char = next_char;
if (next_char == kPlusSign) {
accrued_input_without_formatting_.append(next_char);
} else {
string number;
UnicodeString(next_char).toUTF8String(number);
phone_util_.NormalizeDigitsOnly(&number);
accrued_input_without_formatting_.append(next_char);
national_number_.append(number);
normalized_char = number[0];
}
if (remember_position) {
position_to_remember_ = accrued_input_without_formatting_.length();
}
return normalized_char;
}
void AsYouTypeFormatter::InputDigitHelper(char next_char, string* number) {
DCHECK(number);
number->clear();
const char32 placeholder_codepoint = UnicodeString(kDigitPlaceholder)[0];
int placeholder_pos = formatting_template_
.tempSubString(last_match_position_).indexOf(placeholder_codepoint);
if (placeholder_pos != -1) {
UnicodeString temp_template = formatting_template_;
placeholder_pos = temp_template.indexOf(placeholder_codepoint);
temp_template.setCharAt(placeholder_pos, UnicodeString(next_char)[0]);
last_match_position_ = placeholder_pos;
formatting_template_.replace(0, temp_template.length(), temp_template);
formatting_template_.tempSubString(0, last_match_position_ + 1)
.toUTF8String(*number);
} else {
if (possible_formats_.size() == 1) {
// More digits are entered than we could handle, and there are no other
// valid patterns to try.
able_to_format_ = false;
} // else, we just reset the formatting pattern.
current_formatting_pattern_.clear();
accrued_input_.toUTF8String(*number);
}
}
// Returns the number of bytes contained in the given UnicodeString up to the
// specified position.
// static
int AsYouTypeFormatter::ConvertUnicodeStringPosition(const UnicodeString& s,
int pos) {
if (pos > s.length()) {
return -1;
}
string substring;
s.tempSubString(0, pos).toUTF8String(substring);
return substring.length();
}
} // namespace phonenumbers
} // namespace i18n