#include <string.h>
#include <algorithm>
#include <cctype>
-#include <fstream>
-#include <iostream>
#include <iterator>
#include <map>
-#include <sstream>
#include <utility>
#include <vector>
namespace i18n {
namespace phonenumbers {
-using std::cerr;
-using std::endl;
-using std::ifstream;
-using std::make_pair;
-using std::sort;
-using std::stringstream;
-
using google::protobuf::RepeatedPtrField;
+// static constants
+const size_t PhoneNumberUtil::kMinLengthForNsn;
+const size_t PhoneNumberUtil::kMaxLengthForNsn;
+const size_t PhoneNumberUtil::kMaxLengthCountryCode;
+const int PhoneNumberUtil::kNanpaCountryCode;
+
// static
const char PhoneNumberUtil::kPlusChars[] = "+\xEF\xBC\x8B"; /* "++" */
// To find out the unicode code-point of the characters below in vim, highlight
bool LoadCompiledInMetadata(PhoneMetadataCollection* metadata) {
if (!metadata->ParseFromArray(metadata_get(), metadata_size())) {
- cerr << "Could not parse binary data." << endl;
+ LOG(ERROR) << "Could not parse binary data.";
return false;
}
return true;
first_number_national_number);
}
-bool IsNumberMatchingDesc(const string& national_number,
- const PhoneNumberDesc& number_desc,
- RegExpCache* regexp_cache) {
- return regexp_cache->GetRegExp(number_desc.possible_number_pattern())
- .FullMatch(national_number) &&
- regexp_cache->GetRegExp(number_desc.national_number_pattern())
- .FullMatch(national_number);
-}
-
-PhoneNumberUtil::PhoneNumberType GetNumberTypeHelper(
- const string& national_number, const PhoneMetadata& metadata,
- RegExpCache* regexp_cache) {
- const PhoneNumberDesc& general_desc = metadata.general_desc();
- if (!general_desc.has_national_number_pattern() ||
- !IsNumberMatchingDesc(national_number, general_desc, regexp_cache)) {
- VLOG(4) << "Number type unknown - doesn't match general national number"
- << " pattern.";
- return PhoneNumberUtil::UNKNOWN;
- }
- if (IsNumberMatchingDesc(national_number, metadata.premium_rate(),
- regexp_cache)) {
- VLOG(4) << "Number is a premium number.";
- return PhoneNumberUtil::PREMIUM_RATE;
- }
- if (IsNumberMatchingDesc(national_number, metadata.toll_free(),
- regexp_cache)) {
- VLOG(4) << "Number is a toll-free number.";
- return PhoneNumberUtil::TOLL_FREE;
- }
- if (IsNumberMatchingDesc(national_number, metadata.shared_cost(),
- regexp_cache)) {
- VLOG(4) << "Number is a shared cost number.";
- return PhoneNumberUtil::SHARED_COST;
- }
- if (IsNumberMatchingDesc(national_number, metadata.voip(), regexp_cache)) {
- VLOG(4) << "Number is a VOIP (Voice over IP) number.";
- return PhoneNumberUtil::VOIP;
- }
- if (IsNumberMatchingDesc(national_number, metadata.personal_number(),
- regexp_cache)) {
- VLOG(4) << "Number is a personal number.";
- return PhoneNumberUtil::PERSONAL_NUMBER;
- }
- if (IsNumberMatchingDesc(national_number, metadata.pager(), regexp_cache)) {
- VLOG(4) << "Number is a pager number.";
- return PhoneNumberUtil::PAGER;
- }
- if (IsNumberMatchingDesc(national_number, metadata.uan(), regexp_cache)) {
- VLOG(4) << "Number is a UAN.";
- return PhoneNumberUtil::UAN;
- }
- if (IsNumberMatchingDesc(national_number, metadata.voicemail(),
- regexp_cache)) {
- VLOG(4) << "Number is a voicemail number.";
- return PhoneNumberUtil::VOICEMAIL;
- }
-
- bool is_fixed_line =
- IsNumberMatchingDesc(national_number, metadata.fixed_line(),
- regexp_cache);
- if (is_fixed_line) {
- if (metadata.same_mobile_and_fixed_line_pattern()) {
- VLOG(4) << "Fixed-line and mobile patterns equal, number is fixed-line"
- << " or mobile";
- return PhoneNumberUtil::FIXED_LINE_OR_MOBILE;
- } else if (IsNumberMatchingDesc(national_number, metadata.mobile(),
- regexp_cache)) {
- VLOG(4) << "Fixed-line and mobile patterns differ, but number is "
- << "still fixed-line or mobile";
- return PhoneNumberUtil::FIXED_LINE_OR_MOBILE;
- }
- VLOG(4) << "Number is a fixed line number.";
- return PhoneNumberUtil::FIXED_LINE;
- }
- // Otherwise, test to see if the number is mobile. Only do this if certain
- // that the patterns for mobile and fixed line aren't the same.
- if (!metadata.same_mobile_and_fixed_line_pattern() &&
- IsNumberMatchingDesc(national_number, metadata.mobile(), regexp_cache)) {
- VLOG(4) << "Number is a mobile number.";
- return PhoneNumberUtil::MOBILE;
- }
- VLOG(4) << "Number type unknown - doesn\'t match any specific number type"
- << " pattern.";
- return PhoneNumberUtil::UNKNOWN;
-}
-
char32 ToUnicodeCodepoint(const char* unicode_char) {
char32 codepoint;
EncodingUtils::DecodeUTF8Char(unicode_char, &codepoint);
class PhoneNumberRegExpsAndMappings {
private:
void InitializeMapsAndSets() {
- diallable_char_mappings_.insert(make_pair('+', '+'));
- diallable_char_mappings_.insert(make_pair('*', '*'));
+ diallable_char_mappings_.insert(std::make_pair('+', '+'));
+ diallable_char_mappings_.insert(std::make_pair('*', '*'));
// Here we insert all punctuation symbols that we wish to respect when
// formatting alpha numbers, as they show the intended number groupings.
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("-"), '-'));
+ std::make_pair(ToUnicodeCodepoint("-"), '-'));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("\xEF\xBC\x8D" /* "-" */), '-'));
+ std::make_pair(ToUnicodeCodepoint("\xEF\xBC\x8D" /* "-" */), '-'));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("\xE2\x80\x90" /* "‐" */), '-'));
+ std::make_pair(ToUnicodeCodepoint("\xE2\x80\x90" /* "‐" */), '-'));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("\xE2\x80\x91" /* "‑" */), '-'));
+ std::make_pair(ToUnicodeCodepoint("\xE2\x80\x91" /* "‑" */), '-'));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("\xE2\x80\x92" /* "‒" */), '-'));
+ std::make_pair(ToUnicodeCodepoint("\xE2\x80\x92" /* "‒" */), '-'));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("\xE2\x80\x93" /* "–" */), '-'));
+ std::make_pair(ToUnicodeCodepoint("\xE2\x80\x93" /* "–" */), '-'));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("\xE2\x80\x94" /* "—" */), '-'));
+ std::make_pair(ToUnicodeCodepoint("\xE2\x80\x94" /* "—" */), '-'));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("\xE2\x80\x95" /* "―" */), '-'));
+ std::make_pair(ToUnicodeCodepoint("\xE2\x80\x95" /* "―" */), '-'));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("\xE2\x88\x92" /* "−" */), '-'));
+ std::make_pair(ToUnicodeCodepoint("\xE2\x88\x92" /* "−" */), '-'));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("/"), '/'));
+ std::make_pair(ToUnicodeCodepoint("/"), '/'));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("\xEF\xBC\x8F" /* "/" */), '/'));
+ std::make_pair(ToUnicodeCodepoint("\xEF\xBC\x8F" /* "/" */), '/'));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint(" "), ' '));
+ std::make_pair(ToUnicodeCodepoint(" "), ' '));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("\xE3\x80\x80" /* " " */), ' '));
+ std::make_pair(ToUnicodeCodepoint("\xE3\x80\x80" /* " " */), ' '));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("\xE2\x81\xA0"), ' '));
+ std::make_pair(ToUnicodeCodepoint("\xE2\x81\xA0"), ' '));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("."), '.'));
+ std::make_pair(ToUnicodeCodepoint("."), '.'));
all_plus_number_grouping_symbols_.insert(
- make_pair(ToUnicodeCodepoint("\xEF\xBC\x8E" /* "." */), '.'));
+ std::make_pair(ToUnicodeCodepoint("\xEF\xBC\x8E" /* "." */), '.'));
// Only the upper-case letters are added here - the lower-case versions are
// added programmatically.
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("A"), '2'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("B"), '2'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("C"), '2'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("D"), '3'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("E"), '3'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("F"), '3'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("G"), '4'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("H"), '4'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("I"), '4'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("J"), '5'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("K"), '5'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("L"), '5'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("M"), '6'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("N"), '6'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("O"), '6'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("P"), '7'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("Q"), '7'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("R"), '7'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("S"), '7'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("T"), '8'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("U"), '8'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("V"), '8'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("W"), '9'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("X"), '9'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("Y"), '9'));
- alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("Z"), '9'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("A"), '2'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("B"), '2'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("C"), '2'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("D"), '3'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("E"), '3'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("F"), '3'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("G"), '4'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("H"), '4'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("I"), '4'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("J"), '5'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("K"), '5'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("L"), '5'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("M"), '6'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("N"), '6'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("O"), '6'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("P"), '7'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("Q"), '7'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("R"), '7'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("S"), '7'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("T"), '8'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("U"), '8'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("V"), '8'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("W"), '9'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("X"), '9'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("Y"), '9'));
+ alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("Z"), '9'));
map<char32, char> lower_case_mappings;
map<char32, char> alpha_letters;
for (map<char32, char>::const_iterator it = alpha_mappings_.begin();
if (it->first < 128) {
char letter_as_upper = static_cast<char>(it->first);
char32 letter_as_lower = static_cast<char32>(tolower(letter_as_upper));
- lower_case_mappings.insert(make_pair(letter_as_lower, it->second));
+ lower_case_mappings.insert(std::make_pair(letter_as_lower, it->second));
// Add the letters in both variants to the alpha_letters map. This just
// pairs each letter with its upper-case representation so that it can
// be retained when normalising alpha numbers.
- alpha_letters.insert(make_pair(letter_as_lower, letter_as_upper));
- alpha_letters.insert(make_pair(it->first, letter_as_upper));
+ alpha_letters.insert(std::make_pair(letter_as_lower, letter_as_upper));
+ alpha_letters.insert(std::make_pair(it->first, letter_as_upper));
}
}
// In the Java version we don't insert the lower-case mappings in the map,
alpha_letters.end());
// Add the ASCII digits so that they don't get deleted by NormalizeHelper().
for (char c = '0'; c <= '9'; ++c) {
- diallable_char_mappings_.insert(make_pair(c, c));
- alpha_phone_mappings_.insert(make_pair(c, c));
- all_plus_number_grouping_symbols_.insert(make_pair(c, c));
+ diallable_char_mappings_.insert(std::make_pair(c, c));
+ alpha_phone_mappings_.insert(std::make_pair(c, c));
+ all_plus_number_grouping_symbols_.insert(std::make_pair(c, c));
}
- mobile_token_mappings_.insert(make_pair(52, '1'));
- mobile_token_mappings_.insert(make_pair(54, '9'));
+ mobile_token_mappings_.insert(std::make_pair(52, '1'));
+ mobile_token_mappings_.insert(std::make_pair(54, '9'));
}
// Small string helpers since StrCat has a maximum number of arguments. These
int country_calling_code = it->country_code();
if (kRegionCodeForNonGeoEntity == region_code) {
country_code_to_non_geographical_metadata_map_->insert(
- make_pair(country_calling_code, *it));
+ std::make_pair(country_calling_code, *it));
} else {
- region_to_metadata_map_->insert(make_pair(region_code, *it));
+ region_to_metadata_map_->insert(std::make_pair(region_code, *it));
}
map<int, list<string>* >::iterator calling_code_in_map =
country_calling_code_to_region_map.find(country_calling_code);
list<string>* list_with_region_code = new list<string>();
list_with_region_code->push_back(region_code);
country_calling_code_to_region_map.insert(
- make_pair(country_calling_code, list_with_region_code));
+ std::make_pair(country_calling_code, list_with_region_code));
}
if (country_calling_code == kNanpaCountryCode) {
nanpa_regions_->insert(region_code);
country_calling_code_to_region_map.begin(),
country_calling_code_to_region_map.end());
// Sort all the pairs in ascending order according to country calling code.
- sort(country_calling_code_to_region_code_map_->begin(),
- country_calling_code_to_region_code_map_->end(),
- OrderByFirst());
+ std::sort(country_calling_code_to_region_code_map_->begin(),
+ country_calling_code_to_region_code_map_->end(),
+ OrderByFirst());
}
PhoneNumberUtil::~PhoneNumberUtil() {
}
}
+void PhoneNumberUtil::GetSupportedGlobalNetworkCallingCodes(
+ set<int>* calling_codes) const {
+ DCHECK(calling_codes);
+ for (map<int, PhoneMetadata>::const_iterator it =
+ country_code_to_non_geographical_metadata_map_->begin();
+ it != country_code_to_non_geographical_metadata_map_->end(); ++it) {
+ calling_codes->insert(it->first);
+ }
+}
+
// Public wrapper function to get a PhoneNumberUtil instance with the default
// metadata file.
// static
number_no_extension.clear_extension();
string region_code;
GetRegionCodeForCountryCode(country_calling_code, ®ion_code);
+ PhoneNumberType number_type = GetNumberType(number_no_extension);
+ bool is_valid_number = (number_type != UNKNOWN);
if (calling_from == region_code) {
- PhoneNumberType number_type = GetNumberType(number_no_extension);
bool is_fixed_line_or_mobile =
(number_type == FIXED_LINE) || (number_type == MOBILE) ||
(number_type == FIXED_LINE_OR_MOBILE);
// string here.
formatted_number->assign("");
}
- } else if (region_code == "HU") {
+ } else if (is_valid_number && region_code == "HU") {
// The national format for HU numbers doesn't contain the national prefix,
// because that is how numbers are normally written down. However, the
- // national prefix is obligatory when dialing from a mobile phone. As a
- // result, we add it back here.
+ // national prefix is obligatory when dialing from a mobile phone, except
+ // for short numbers. As a result, we add it back here if it is a valid
+ // regular length phone number.
Format(number_no_extension, NATIONAL, formatted_number);
string hu_national_prefix;
GetNddPrefixForRegion(region_code, true /* strip non-digits */,
&hu_national_prefix);
formatted_number->assign(
StrCat(hu_national_prefix, " ", *formatted_number));
+ } else if (country_calling_code == kNanpaCountryCode) {
+ // For NANPA countries, we output international format for numbers that
+ // can be dialed internationally, since that always works, except for
+ // numbers which might potentially be short numbers, which are always
+ // dialled in national format.
+ const PhoneMetadata* region_metadata = GetMetadataForRegion(calling_from);
+ string national_number;
+ GetNationalSignificantNumber(number_no_extension, &national_number);
+ if (CanBeInternationallyDialled(number_no_extension) &&
+ !IsShorterThanPossibleNormalNumber(region_metadata,
+ national_number)) {
+ Format(number_no_extension, INTERNATIONAL, formatted_number);
+ } else {
+ Format(number_no_extension, NATIONAL, formatted_number);
+ }
} else {
- // For NANPA countries, non-geographical countries, Mexican and Chilean
- // fixed line and mobile numbers, we output international format for
- // numbers that can be dialed internationally as that always works.
- if ((country_calling_code == kNanpaCountryCode ||
- region_code == kRegionCodeForNonGeoEntity ||
+ // For non-geographical countries, and Mexican and Chilean fixed line and
+ // mobile numbers, we output international format for numbers that can be
+ // dialed internationally as that always works.
+ if ((region_code == kRegionCodeForNonGeoEntity ||
// MX fixed line and mobile numbers should always be formatted in
// international format, even when dialed within MX. For national
// format to work, a carrier code needs to be used, and the correct
Format(number_no_extension, NATIONAL, formatted_number);
}
}
- } else if (CanBeInternationallyDialled(number_no_extension)) {
+ } else if (is_valid_number &&
+ CanBeInternationallyDialled(number_no_extension)) {
+ // We assume that short numbers are not diallable from outside their
+ // region, so if a number is not a valid regular length phone number, we
+ // treat it as if it cannot be internationally dialled.
with_formatting
? Format(number_no_extension, INTERNATIONAL, formatted_number)
: Format(number_no_extension, E164, formatted_number);
*region_code = *it;
return;
}
- } else if (GetNumberTypeHelper(national_number, *metadata,
- reg_exps_->regexp_cache_.get()) != UNKNOWN) {
+ } else if (GetNumberTypeHelper(national_number, *metadata) != UNKNOWN) {
*region_code = *it;
return;
}
// Now append everything between the "tel:" prefix and the phone-context.
// This should include the national number, an optional extension or
- // isdn-subaddress component.
- int end_of_rfc_prefix =
- number_to_parse.find(kRfc3966Prefix) + strlen(kRfc3966Prefix);
+ // isdn-subaddress component. Note we also handle the case when "tel:" is
+ // missing, as we have seen in some of the phone number inputs. In that
+ // case, we append everything from the beginning.
+ size_t index_of_rfc_prefix = number_to_parse.find(kRfc3966Prefix);
+ int index_of_national_number = (index_of_rfc_prefix != string::npos) ?
+ index_of_rfc_prefix + strlen(kRfc3966Prefix) : 0;
StrAppend(
national_number,
- number_to_parse.substr(end_of_rfc_prefix,
- index_of_phone_context - end_of_rfc_prefix));
+ number_to_parse.substr(
+ index_of_national_number,
+ index_of_phone_context - index_of_national_number));
} else {
// Extract a possible number from the string passed in (this strips leading
// characters that could not be the start of a phone number.)
return TOO_SHORT_NSN;
}
if (country_metadata) {
- string* carrier_code = keep_raw_input ?
- temp_number.mutable_preferred_domestic_carrier_code() : NULL;
+ string carrier_code;
+ string potential_national_number(normalized_national_number);
MaybeStripNationalPrefixAndCarrierCode(*country_metadata,
- &normalized_national_number,
- carrier_code);
+ &potential_national_number,
+ &carrier_code);
+ // We require that the NSN remaining after stripping the national prefix
+ // and carrier code be of a possible length for the region. Otherwise, we
+ // don't do the stripping, since the original number could be a valid short
+ // number.
+ if (!IsShorterThanPossibleNormalNumber(country_metadata,
+ potential_national_number)) {
+ normalized_national_number.assign(potential_national_number);
+ if (keep_raw_input) {
+ temp_number.set_preferred_domestic_carrier_code(carrier_code);
+ }
+ }
}
size_t normalized_national_number_length =
normalized_national_number.length();
return TOO_LONG_NSN;
}
temp_number.set_country_code(country_code);
- if (normalized_national_number[0] == '0') {
- temp_number.set_italian_leading_zero(true);
- }
+ SetItalianLeadingZerosForPhoneNumber(normalized_national_number,
+ &temp_number);
uint64 number_as_int;
safe_strtou64(normalized_national_number, &number_as_int);
temp_number.set_national_number(number_as_int);
- phone_number->MergeFrom(temp_number);
+ phone_number->Swap(&temp_number);
return NO_PARSING_ERROR;
}
// Metadata cannot be NULL because the country calling code is valid.
const PhoneMetadata* metadata =
GetMetadataForRegionOrCallingCode(country_code, region_code);
- const PhoneNumberDesc& general_num_desc = metadata->general_desc();
- // Handling case of numbers with no metadata.
- if (!general_num_desc.has_national_number_pattern()) {
- size_t number_length = national_number.length();
- if (number_length < kMinLengthForNsn) {
- return TOO_SHORT;
- } else if (number_length > kMaxLengthForNsn) {
- return TOO_LONG;
- } else {
- return IS_POSSIBLE;
- }
- }
const RegExp& possible_number_pattern = reg_exps_->regexp_cache_->GetRegExp(
- StrCat("(", general_num_desc.possible_number_pattern(), ")"));
+ StrCat("(", metadata->general_desc().possible_number_pattern(), ")"));
return TestNumberLengthAgainstPattern(possible_number_pattern,
national_number);
}
}
string national_significant_number;
GetNationalSignificantNumber(number, &national_significant_number);
- return GetNumberTypeHelper(national_significant_number,
- *metadata,
- reg_exps_->regexp_cache_.get());
+ return GetNumberTypeHelper(national_significant_number, *metadata);
}
bool PhoneNumberUtil::IsValidNumber(const PhoneNumber& number) const {
// number does not match that of the region code.
return false;
}
- const PhoneNumberDesc& general_desc = metadata->general_desc();
string national_number;
GetNationalSignificantNumber(number, &national_number);
- // For regions where we don't have metadata for PhoneNumberDesc, we treat
- // any number passed in as a valid number if its national significant number
- // is between the minimum and maximum lengths defined by ITU for a national
- // significant number.
- if (!general_desc.has_national_number_pattern()) {
- VLOG(3) << "Validating number with incomplete metadata.";
- size_t number_length = national_number.length();
- return number_length > kMinLengthForNsn &&
- number_length <= kMaxLengthForNsn;
- }
- return GetNumberTypeHelper(national_number, *metadata,
- reg_exps_->regexp_cache_.get()) != UNKNOWN;
+ return GetNumberTypeHelper(national_number, *metadata) != UNKNOWN;
}
bool PhoneNumberUtil::IsNumberGeographical(
return main_metadata_for_calling_code->leading_zero_possible();
}
+// A helper function to set the values related to leading zeros in a
+// PhoneNumber.
+void PhoneNumberUtil::SetItalianLeadingZerosForPhoneNumber(
+ const string& national_number, PhoneNumber* phone_number) const {
+ if (national_number.length() > 1 && national_number[0] == '0') {
+ phone_number->set_italian_leading_zero(true);
+ size_t number_of_leading_zeros = 1;
+ // Note that if the national number is all "0"s, the last "0" is not
+ // counted as a leading zero.
+ while (number_of_leading_zeros < national_number.length() - 1 &&
+ national_number[number_of_leading_zeros] == '0') {
+ number_of_leading_zeros++;
+ }
+ if (number_of_leading_zeros != 1) {
+ phone_number->set_number_of_leading_zeros(number_of_leading_zeros);
+ }
+ }
+}
+
+bool PhoneNumberUtil::IsNumberPossibleForDesc(
+ const string& national_number, const PhoneNumberDesc& number_desc) const {
+ return reg_exps_->regexp_cache_.get()->
+ GetRegExp(number_desc.possible_number_pattern())
+ .FullMatch(national_number);
+}
+
+bool PhoneNumberUtil::IsNumberMatchingDesc(
+ const string& national_number, const PhoneNumberDesc& number_desc) const {
+ return IsNumberPossibleForDesc(national_number, number_desc) &&
+ reg_exps_->regexp_cache_.get()->
+ GetRegExp(number_desc.national_number_pattern())
+ .FullMatch(national_number);
+}
+
+PhoneNumberUtil::PhoneNumberType PhoneNumberUtil::GetNumberTypeHelper(
+ const string& national_number, const PhoneMetadata& metadata) const {
+ if (!IsNumberMatchingDesc(national_number, metadata.general_desc())) {
+ VLOG(4) << "Number type unknown - doesn't match general national number"
+ << " pattern.";
+ return PhoneNumberUtil::UNKNOWN;
+ }
+ if (IsNumberMatchingDesc(national_number, metadata.premium_rate())) {
+ VLOG(4) << "Number is a premium number.";
+ return PhoneNumberUtil::PREMIUM_RATE;
+ }
+ if (IsNumberMatchingDesc(national_number, metadata.toll_free())) {
+ VLOG(4) << "Number is a toll-free number.";
+ return PhoneNumberUtil::TOLL_FREE;
+ }
+ if (IsNumberMatchingDesc(national_number, metadata.shared_cost())) {
+ VLOG(4) << "Number is a shared cost number.";
+ return PhoneNumberUtil::SHARED_COST;
+ }
+ if (IsNumberMatchingDesc(national_number, metadata.voip())) {
+ VLOG(4) << "Number is a VOIP (Voice over IP) number.";
+ return PhoneNumberUtil::VOIP;
+ }
+ if (IsNumberMatchingDesc(national_number, metadata.personal_number())) {
+ VLOG(4) << "Number is a personal number.";
+ return PhoneNumberUtil::PERSONAL_NUMBER;
+ }
+ if (IsNumberMatchingDesc(national_number, metadata.pager())) {
+ VLOG(4) << "Number is a pager number.";
+ return PhoneNumberUtil::PAGER;
+ }
+ if (IsNumberMatchingDesc(national_number, metadata.uan())) {
+ VLOG(4) << "Number is a UAN.";
+ return PhoneNumberUtil::UAN;
+ }
+ if (IsNumberMatchingDesc(national_number, metadata.voicemail())) {
+ VLOG(4) << "Number is a voicemail number.";
+ return PhoneNumberUtil::VOICEMAIL;
+ }
+
+ bool is_fixed_line =
+ IsNumberMatchingDesc(national_number, metadata.fixed_line());
+ if (is_fixed_line) {
+ if (metadata.same_mobile_and_fixed_line_pattern()) {
+ VLOG(4) << "Fixed-line and mobile patterns equal, number is fixed-line"
+ << " or mobile";
+ return PhoneNumberUtil::FIXED_LINE_OR_MOBILE;
+ } else if (IsNumberMatchingDesc(national_number, metadata.mobile())) {
+ VLOG(4) << "Fixed-line and mobile patterns differ, but number is "
+ << "still fixed-line or mobile";
+ return PhoneNumberUtil::FIXED_LINE_OR_MOBILE;
+ }
+ VLOG(4) << "Number is a fixed line number.";
+ return PhoneNumberUtil::FIXED_LINE;
+ }
+ // Otherwise, test to see if the number is mobile. Only do this if certain
+ // that the patterns for mobile and fixed line aren't the same.
+ if (!metadata.same_mobile_and_fixed_line_pattern() &&
+ IsNumberMatchingDesc(national_number, metadata.mobile())) {
+ VLOG(4) << "Number is a mobile number.";
+ return PhoneNumberUtil::MOBILE;
+ }
+ VLOG(4) << "Number type unknown - doesn\'t match any specific number type"
+ << " pattern.";
+ return PhoneNumberUtil::UNKNOWN;
+}
+
void PhoneNumberUtil::GetNationalSignificantNumber(
const PhoneNumber& number,
string* national_number) const {
DCHECK(national_number);
- // If a leading zero has been set, we prefix this now. Note this is not a
+ // If leading zero(s) have been set, we prefix this now. Note this is not a
// national prefix.
- StrAppend(national_number, number.italian_leading_zero() ? "0" : "");
+ StrAppend(national_number, number.italian_leading_zero() ?
+ string(number.number_of_leading_zeros(), '0') : "");
StrAppend(national_number, number.national_number());
}
return new AsYouTypeFormatter(region_code);
}
+bool PhoneNumberUtil::IsShorterThanPossibleNormalNumber(
+ const PhoneMetadata* country_metadata, const string& number) const {
+ const RegExp& possible_number_pattern =
+ reg_exps_->regexp_cache_->GetRegExp(StrCat("(",
+ country_metadata->general_desc().possible_number_pattern(), ")"));
+ return TestNumberLengthAgainstPattern(possible_number_pattern, number) ==
+ PhoneNumberUtil::TOO_SHORT;
+}
+
bool PhoneNumberUtil::CanBeInternationallyDialled(
const PhoneNumber& number) const {
string region_code;
string national_significant_number;
GetNationalSignificantNumber(number, &national_significant_number);
return !IsNumberMatchingDesc(
- national_significant_number, metadata->no_international_dialling(),
- reg_exps_->regexp_cache_.get());
+ national_significant_number, metadata->no_international_dialling());
}
} // namespace phonenumbers