JS/C++: Added mobile token support to phone number util
authorroes@google.com <roes@google.com@ee073f10-1060-11df-b6a4-87a95322a99c>
Tue, 8 Oct 2013 13:09:13 +0000 (13:09 +0000)
committerroes@google.com <roes@google.com@ee073f10-1060-11df-b6a4-87a95322a99c>
Tue, 8 Oct 2013 13:09:13 +0000 (13:09 +0000)
git-svn-id: http://libphonenumber.googlecode.com/svn/trunk@619 ee073f10-1060-11df-b6a4-87a95322a99c

cpp/src/phonenumbers/phonenumberutil.cc
cpp/src/phonenumbers/phonenumberutil.h
cpp/test/phonenumbers/geocoding/geocoding_data_test.cc
cpp/test/phonenumbers/phonenumberutil_test.cc
javascript/i18n/phonenumbers/phonenumberutil.js
javascript/i18n/phonenumbers/phonenumberutil_test.js

index 41cfd34..d966a35 100644 (file)
@@ -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<char32, char> 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<int, char> 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(), &region_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<int, char>::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(
index ca5bdd0..195628f 100644 (file)
@@ -272,6 +272,13 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
   // 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
index a3b7a19..53a02df 100644 (file)
@@ -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]);
index d9c766b..9347f19 100644 (file)
@@ -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.
index 8264604..4c9d84c 100644 (file)
@@ -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.<number, string>}
+ * @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.
index 5e29a90..8e1b006 100644 (file)
@@ -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));