From 0cadbd198539bb98baf4580df7087ce126965466 Mon Sep 17 00:00:00 2001 From: "roes@google.com" Date: Tue, 8 Oct 2013 13:09:13 +0000 Subject: [PATCH] JS/C++: Added mobile token support to phone number util git-svn-id: http://libphonenumber.googlecode.com/svn/trunk@619 ee073f10-1060-11df-b6a4-87a95322a99c --- cpp/src/phonenumbers/phonenumberutil.cc | 44 +++++++++++++---- cpp/src/phonenumbers/phonenumberutil.h | 7 +++ .../phonenumbers/geocoding/geocoding_data_test.cc | 8 +-- cpp/test/phonenumbers/phonenumberutil_test.cc | 19 ++++++++ javascript/i18n/phonenumbers/phonenumberutil.js | 57 +++++++++++++++++----- .../i18n/phonenumbers/phonenumberutil_test.js | 9 ++++ 6 files changed, 120 insertions(+), 24 deletions(-) diff --git a/cpp/src/phonenumbers/phonenumberutil.cc b/cpp/src/phonenumbers/phonenumberutil.cc index 41cfd34..d966a35 100644 --- a/cpp/src/phonenumbers/phonenumberutil.cc +++ b/cpp/src/phonenumbers/phonenumberutil.cc @@ -473,6 +473,9 @@ class PhoneNumberRegExpsAndMappings { alpha_phone_mappings_.insert(make_pair(c, c)); all_plus_number_grouping_symbols_.insert(make_pair(c, c)); } + + mobile_token_mappings_.insert(make_pair(52, '1')); + mobile_token_mappings_.insert(make_pair(54, '9')); } // Small string helpers since StrCat has a maximum number of arguments. These @@ -526,6 +529,12 @@ class PhoneNumberRegExpsAndMappings { // such as "-" and " ". map all_plus_number_grouping_symbols_; + // Map of country calling codes that use a mobile token before the area code. + // One example of when this is relevant is when determining the length of the + // national destination code, which should be the length of the area code plus + // the length of the mobile token. + map mobile_token_mappings_; + // Pattern that makes it easy to distinguish whether a region has a unique // international dialing prefix or not. If a region has a unique international // prefix (e.g. 011 in USA), it will be represented as a string that contains @@ -610,6 +619,7 @@ class PhoneNumberRegExpsAndMappings { alpha_mappings_(), alpha_phone_mappings_(), all_plus_number_grouping_symbols_(), + mobile_token_mappings_(), unique_international_prefix_(regexp_factory_->CreateRegExp( /* "[\\d]+(?:[~⁓∼~][\\d]+)?" */ "[\\d]+(?:[~\xE2\x81\x93\xE2\x88\xBC\xEF\xBD\x9E][\\d]+)?")), @@ -2185,19 +2195,35 @@ int PhoneNumberUtil::GetLengthOfNationalDestinationCode( third_group = digit_group; } } - string region_code; - GetRegionCodeForCountryCode(number.country_code(), ®ion_code); - if (region_code == "AR" && - GetNumberType(number) == MOBILE) { - // Argentinian mobile numbers, when formatted in the international format, - // are in the form of +54 9 NDC XXXX.... As a result, we take the length of - // the third group (NDC) and add 1 for the digit 9, which also forms part of - // the national significant number. - return third_group.size() + 1; + + if (GetNumberType(number) == MOBILE) { + // For example Argentinian mobile numbers, when formatted in the + // international format, are in the form of +54 9 NDC XXXX.... As a result, + // we take the length of the third group (NDC) and add the length of the + // mobile token, which also forms part of the national significant number. + // This assumes that the mobile token is always formatted separately from + // the rest of the phone number. + string mobile_token; + GetCountryMobileToken(number.country_code(), &mobile_token); + if (!mobile_token.empty()) { + return third_group.size() + mobile_token.size(); + } } return ndc.size(); } +void PhoneNumberUtil::GetCountryMobileToken(int country_calling_code, + string* mobile_token) const { + DCHECK(mobile_token); + map::iterator it = reg_exps_->mobile_token_mappings_.find( + country_calling_code); + if (it != reg_exps_->mobile_token_mappings_.end()) { + *mobile_token = it->second; + } else { + mobile_token->assign(""); + } +} + void PhoneNumberUtil::NormalizeDigitsOnly(string* number) const { DCHECK(number); const RegExp& non_digits_pattern = reg_exps_->regexp_cache_->GetRegExp( diff --git a/cpp/src/phonenumbers/phonenumberutil.h b/cpp/src/phonenumbers/phonenumberutil.h index ca5bdd0..195628f 100644 --- a/cpp/src/phonenumbers/phonenumberutil.h +++ b/cpp/src/phonenumbers/phonenumberutil.h @@ -272,6 +272,13 @@ class PhoneNumberUtil : public Singleton { // GetLengthOfGeographicalAreaCode(). int GetLengthOfNationalDestinationCode(const PhoneNumber& number) const; + // Returns the mobile token for the provided country calling code if it has + // one, otherwise returns an empty string. A mobile token is a number inserted + // before the area code when dialing a mobile number from that country from + // abroad. + void GetCountryMobileToken(int country_calling_code, + string* mobile_token) const; + // Formats a phone number in the specified format using default rules. Note // that this does not promise to produce a phone number that the user can // dial from where they are - although we do format in either NATIONAL or diff --git a/cpp/test/phonenumbers/geocoding/geocoding_data_test.cc b/cpp/test/phonenumbers/geocoding/geocoding_data_test.cc index a3b7a19..53a02df 100644 --- a/cpp/test/phonenumbers/geocoding/geocoding_data_test.cc +++ b/cpp/test/phonenumbers/geocoding/geocoding_data_test.cc @@ -130,9 +130,9 @@ TEST(GeocodingDataTest, TestTestPrefixDescriptions) { } TEST(GeocodingDataTest, TestTestGeocodingData) { - ASSERT_EQ(2, get_test_country_calling_codes_size()); + ASSERT_EQ(3, get_test_country_calling_codes_size()); const int* country_calling_codes = get_test_country_calling_codes(); - const int expected_calling_codes[] = {1, 82}; + const int expected_calling_codes[] = {1, 54, 82}; for (int i = 0; i < get_test_country_calling_codes_size(); ++i) { EXPECT_EQ(expected_calling_codes[i], country_calling_codes[i]); } @@ -144,10 +144,10 @@ TEST(GeocodingDataTest, TestTestGeocodingData) { EXPECT_STREQ(expected_languages[i], langs_1->available_languages[i]); } - ASSERT_EQ(4, get_test_prefix_language_code_pairs_size()); + ASSERT_EQ(5, get_test_prefix_language_code_pairs_size()); const char** language_code_pairs = get_test_prefix_language_code_pairs(); const char* expected_language_code_pairs[] = { - "1_de", "1_en", "82_en", "82_ko", + "1_de", "1_en", "54_en", "82_en", "82_ko", }; for (int i = 0; i < get_test_prefix_language_code_pairs_size(); ++i) { EXPECT_STREQ(expected_language_code_pairs[i], language_code_pairs[i]); diff --git a/cpp/test/phonenumbers/phonenumberutil_test.cc b/cpp/test/phonenumbers/phonenumberutil_test.cc index d9c766b..9347f19 100644 --- a/cpp/test/phonenumbers/phonenumberutil_test.cc +++ b/cpp/test/phonenumbers/phonenumberutil_test.cc @@ -1281,6 +1281,11 @@ TEST_F(PhoneNumberUtilTest, GetLengthOfNationalDestinationCode) { number.set_national_number(1155303000ULL); EXPECT_EQ(2, phone_util_.GetLengthOfNationalDestinationCode(number)); + // An Argentinian mobile which has NDC "911". + number.set_country_code(54); + number.set_national_number(91187654321ULL); + EXPECT_EQ(3, phone_util_.GetLengthOfNationalDestinationCode(number)); + // Google Sydney, which has NDC "2". number.set_country_code(61); number.set_national_number(293744000ULL); @@ -1320,6 +1325,20 @@ TEST_F(PhoneNumberUtilTest, GetLengthOfNationalDestinationCode) { EXPECT_EQ(4, phone_util_.GetLengthOfNationalDestinationCode(number)); } +TEST_F(PhoneNumberUtilTest, GetCountryMobileToken) { + int country_calling_code; + string mobile_token; + + country_calling_code = phone_util_.GetCountryCodeForRegion(RegionCode::MX()); + phone_util_.GetCountryMobileToken(country_calling_code, &mobile_token); + EXPECT_EQ("1", mobile_token); + + // Country calling code for United States, which has no mobile token. + country_calling_code = phone_util_.GetCountryCodeForRegion(RegionCode::US()); + phone_util_.GetCountryMobileToken(country_calling_code, &mobile_token); + EXPECT_EQ("", mobile_token); +} + TEST_F(PhoneNumberUtilTest, ExtractPossibleNumber) { // Removes preceding funky punctuation and letters but leaves the rest // untouched. diff --git a/javascript/i18n/phonenumbers/phonenumberutil.js b/javascript/i18n/phonenumbers/phonenumberutil.js index 8264604..4c9d84c 100644 --- a/javascript/i18n/phonenumbers/phonenumberutil.js +++ b/javascript/i18n/phonenumbers/phonenumberutil.js @@ -160,6 +160,22 @@ i18n.phonenumbers.PhoneNumberUtil.COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX_ = '3'; /** + * Map of country calling codes that use a mobile token before the area code. + * One example of when this is relevant is when determining the length of the + * national destination code, which should be the length of the area code plus + * the length of the mobile token. + * + * @const + * @type {!Object.} + * @private + */ +i18n.phonenumbers.PhoneNumberUtil.MOBILE_TOKEN_MAPPINGS_ = { + 52: '1', + 54: '9' +}; + + +/** * The PLUS_SIGN signifies the international prefix. * * @const @@ -1217,23 +1233,42 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfNationalDestinationCode = return 0; } - if (this.getRegionCodeForCountryCode(number.getCountryCodeOrDefault()) == - 'AR' && - this.getNumberType(number) == i18n.phonenumbers.PhoneNumberType.MOBILE) { - // Argentinian mobile numbers, when formatted in the international format, - // are in the form of +54 9 NDC XXXX.... As a result, we take the length of - // the third group (NDC) and add 1 for the digit 9, which also forms part of - // the national significant number. - // - // TODO: Investigate the possibility of better modeling the metadata to make - // it easier to obtain the NDC. - return numberGroups[2].length + 1; + if (this.getNumberType(number) == i18n.phonenumbers.PhoneNumberType.MOBILE) { + // For example Argentinian mobile numbers, when formatted in the + // international format, are in the form of +54 9 NDC XXXX.... As a result, + // we take the length of the third group (NDC) and add the length of the + // mobile token, which also forms part of the national significant number. + // This assumes that the mobile token is always formatted separately from + // the rest of the phone number. + /** @type {string} */ + var mobileToken = i18n.phonenumbers.PhoneNumberUtil.getCountryMobileToken( + number.getCountryCodeOrDefault()); + if (mobileToken != '') { + return numberGroups[2].length + mobileToken.length; + } } return numberGroups[1].length; }; /** + * Returns the mobile token for the provided country calling code if it has + * one, otherwise returns an empty string. A mobile token is a number inserted + * before the area code when dialing a mobile number from that country from + * abroad. + * + * @param {number} countryCallingCode the country calling code for which we + * want the mobile token. + * @return {string} the mobile token for the given country calling code. + */ +i18n.phonenumbers.PhoneNumberUtil.getCountryMobileToken = + function(countryCallingCode) { + return i18n.phonenumbers.PhoneNumberUtil.MOBILE_TOKEN_MAPPINGS_[ + countryCallingCode] || ''; +}; + + +/** * Normalizes a string of characters representing a phone number by replacing * all characters found in the accompanying map with the values therein, and * stripping all other characters if removeNonMatches is true. diff --git a/javascript/i18n/phonenumbers/phonenumberutil_test.js b/javascript/i18n/phonenumbers/phonenumberutil_test.js index 5e29a90..8e1b006 100644 --- a/javascript/i18n/phonenumbers/phonenumberutil_test.js +++ b/javascript/i18n/phonenumbers/phonenumberutil_test.js @@ -415,6 +415,15 @@ function testGetLengthOfNationalDestinationCode() { phoneUtil.getLengthOfNationalDestinationCode(INTERNATIONAL_TOLL_FREE)); } +function testGetCountryMobileToken() { + assertEquals('1', i18n.phonenumbers.PhoneNumberUtil.getCountryMobileToken( + phoneUtil.getCountryCodeForRegion(RegionCode.MX))); + + // Country calling code for United States, which has no mobile token. + assertEquals('', i18n.phonenumbers.PhoneNumberUtil.getCountryMobileToken( + phoneUtil.getCountryCodeForRegion(RegionCode.US))); +} + function testGetNationalSignificantNumber() { assertEquals('6502530000', phoneUtil.getNationalSignificantNumber(US_NUMBER)); -- 2.7.4