3 * Copyright (C) 2010 Google Inc.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 * @fileoverview Utility for international phone numbers.
20 * Functionality includes formatting, parsing and validation.
21 * (based on the java implementation).
23 * @author Nikolaos Trogkanis
26 goog.provide('i18n.phonenumbers.PhoneNumberUtil');
28 goog.require('goog.array');
29 goog.require('goog.proto2.PbLiteSerializer');
30 goog.require('goog.string');
31 goog.require('goog.string.StringBuffer');
32 goog.require('i18n.phonenumbers.NumberFormat');
33 goog.require('i18n.phonenumbers.PhoneMetadata');
34 goog.require('i18n.phonenumbers.PhoneMetadataCollection');
35 goog.require('i18n.phonenumbers.PhoneNumber');
36 goog.require('i18n.phonenumbers.PhoneNumber.CountryCodeSource');
37 goog.require('i18n.phonenumbers.PhoneNumberDesc');
38 goog.require('i18n.phonenumbers.metadata');
46 i18n.phonenumbers.PhoneNumberUtil = function() {
48 * A mapping from a region code to the PhoneMetadata for that region.
49 * @type {Object.<string, i18n.phonenumbers.PhoneMetadata>}
51 this.countryToMetadata = {};
53 goog.addSingletonGetter(i18n.phonenumbers.PhoneNumberUtil);
57 * Errors encountered when parsing phone numbers.
61 i18n.phonenumbers.Error = {
62 INVALID_COUNTRY_CODE: 'Invalid country code',
63 // This generally indicates the string passed in had less than 3 digits in it.
64 // More specifically, the number failed to match the regular expression
65 // VALID_PHONE_NUMBER.
66 NOT_A_NUMBER: 'The string supplied did not seem to be a phone number',
67 // This indicates the string started with an international dialing prefix, but
68 // after this was stripped from the number, had less digits than any valid
69 // phone number (including country code) could have.
70 TOO_SHORT_AFTER_IDD: 'Phone number too short after IDD',
71 // This indicates the string, after any country code has been stripped, had
72 // less digits than any
73 // valid phone number could have.
74 TOO_SHORT_NSN: 'The string supplied is too short to be a phone number',
75 // This indicates the string had more digits than any valid phone number could
77 TOO_LONG: 'The string supplied is too long to be a phone number'
86 i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_ = 1;
90 * The minimum length of the national significant number.
96 i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_ = 3;
100 * The maximum length of the national significant number.
106 i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_ = 15;
110 * The maximum length of the country code.
116 i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE_ = 3;
120 * Region-code for the unknown region.
126 i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_ = 'ZZ';
130 * The PLUS_SIGN signifies the international prefix.
135 i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN = '+';
139 * These mappings map a character (key) to a specific digit that should replace
140 * it for normalization purposes. Non-European digits that may be used in phone
141 * numbers are mapped to a European equivalent.
145 i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS = {
156 '\uFF10': '0', // Fullwidth digit 0
157 '\uFF11': '1', // Fullwidth digit 1
158 '\uFF12': '2', // Fullwidth digit 2
159 '\uFF13': '3', // Fullwidth digit 3
160 '\uFF14': '4', // Fullwidth digit 4
161 '\uFF15': '5', // Fullwidth digit 5
162 '\uFF16': '6', // Fullwidth digit 6
163 '\uFF17': '7', // Fullwidth digit 7
164 '\uFF18': '8', // Fullwidth digit 8
165 '\uFF19': '9', // Fullwidth digit 9
166 '\u0660': '0', // Arabic-indic digit 0
167 '\u0661': '1', // Arabic-indic digit 1
168 '\u0662': '2', // Arabic-indic digit 2
169 '\u0663': '3', // Arabic-indic digit 3
170 '\u0664': '4', // Arabic-indic digit 4
171 '\u0665': '5', // Arabic-indic digit 5
172 '\u0666': '6', // Arabic-indic digit 6
173 '\u0667': '7', // Arabic-indic digit 7
174 '\u0668': '8', // Arabic-indic digit 8
175 '\u0669': '9', // Arabic-indic digit 9
176 '\u06F0': '0', // Eastern-Arabic digit 0
177 '\u06F1': '1', // Eastern-Arabic digit 1
178 '\u06F2': '2', // Eastern-Arabic digit 2
179 '\u06F3': '3', // Eastern-Arabic digit 3
180 '\u06F4': '4', // Eastern-Arabic digit 4
181 '\u06F5': '5', // Eastern-Arabic digit 5
182 '\u06F6': '6', // Eastern-Arabic digit 6
183 '\u06F7': '7', // Eastern-Arabic digit 7
184 '\u06F8': '8', // Eastern-Arabic digit 8
185 '\u06F9': '9' // Eastern-Arabic digit 9
190 * Only upper-case variants of alpha characters are stored.
195 i18n.phonenumbers.PhoneNumberUtil.ALPHA_MAPPINGS_ = {
226 * For performance reasons, amalgamate both into one map.
231 i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_ = {
242 '\uFF10': '0', // Fullwidth digit 0
243 '\uFF11': '1', // Fullwidth digit 1
244 '\uFF12': '2', // Fullwidth digit 2
245 '\uFF13': '3', // Fullwidth digit 3
246 '\uFF14': '4', // Fullwidth digit 4
247 '\uFF15': '5', // Fullwidth digit 5
248 '\uFF16': '6', // Fullwidth digit 6
249 '\uFF17': '7', // Fullwidth digit 7
250 '\uFF18': '8', // Fullwidth digit 8
251 '\uFF19': '9', // Fullwidth digit 9
252 '\u0660': '0', // Arabic-indic digit 0
253 '\u0661': '1', // Arabic-indic digit 1
254 '\u0662': '2', // Arabic-indic digit 2
255 '\u0663': '3', // Arabic-indic digit 3
256 '\u0664': '4', // Arabic-indic digit 4
257 '\u0665': '5', // Arabic-indic digit 5
258 '\u0666': '6', // Arabic-indic digit 6
259 '\u0667': '7', // Arabic-indic digit 7
260 '\u0668': '8', // Arabic-indic digit 8
261 '\u0669': '9', // Arabic-indic digit 9
262 '\u06F0': '0', // Eastern-Arabic digit 0
263 '\u06F1': '1', // Eastern-Arabic digit 1
264 '\u06F2': '2', // Eastern-Arabic digit 2
265 '\u06F3': '3', // Eastern-Arabic digit 3
266 '\u06F4': '4', // Eastern-Arabic digit 4
267 '\u06F5': '5', // Eastern-Arabic digit 5
268 '\u06F6': '6', // Eastern-Arabic digit 6
269 '\u06F7': '7', // Eastern-Arabic digit 7
270 '\u06F8': '8', // Eastern-Arabic digit 8
271 '\u06F9': '9', // Eastern-Arabic digit 9
302 * A list of all country codes where national significant numbers (excluding any
303 * national prefix) exist that start with a leading zero.
308 i18n.phonenumbers.PhoneNumberUtil.LEADING_ZERO_COUNTRIES_ = {
311 225: 1, // Cote d'Ivoire
315 242: 1, // Congo (Rep. of the)
317 378: 1, // San Marino
318 379: 1, // Vatican City
324 * Pattern that makes it easy to distinguish whether a country has a unique
325 * international dialing prefix or not. If a country has a unique international
326 * prefix (e.g. 011 in USA), it will be represented as a string that contains a
327 * sequence of ASCII digits. If there are multiple available international
328 * prefixes in a country, they will be represented as a regex string that always
329 * contains character(s) other than ASCII digits. Note this regex also includes
330 * tilde, which signals waiting for the tone.
336 i18n.phonenumbers.PhoneNumberUtil.UNIQUE_INTERNATIONAL_PREFIX_ =
337 /[\d]+(?:[~\u2053\u223C\uFF5E][\d]+)?/;
341 * Regular expression of acceptable punctuation found in phone numbers. This
342 * excludes punctuation found as a leading character only. This consists of dash
343 * characters, white space characters, full stops, slashes, square brackets,
344 * parentheses and tildes. It also includes the letter 'x' as that is found as a
345 * placeholder for carrier information in some phone numbers.
351 i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION_ =
352 '-x\u2010-\u2015\u2212\u30FC\uFF0D-\uFF0F \u00A0\u200B\u2060\u3000()' +
353 '\uFF08\uFF09\uFF3B\uFF3D.\\[\\]/~\u2053\u223C\uFF5E';
357 * Digits accepted in phone numbers (ascii, fullwidth, arabic-indic, and eastern
364 i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ =
365 '0-9\uFF10-\uFF19\u0660-\u0669\u06F0-\u06F9';
369 * We accept alpha characters in phone numbers, ASCII only, upper and lower
376 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ = 'A-Za-z';
384 i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ = '+\uFF0B';
392 i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_PATTERN_ =
393 new RegExp('^[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']+');
401 i18n.phonenumbers.PhoneNumberUtil.CAPTURING_DIGIT_PATTERN_ =
402 new RegExp('([' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + '])');
406 * Regular expression of acceptable characters that may start a phone number for
407 * the purposes of parsing. This allows us to strip away meaningless prefixes to
408 * phone numbers that may be mistakenly given to us. This consists of digits,
409 * the plus symbol and arabic-indic digits. This does not contain alpha
410 * characters, although they may be used later in the number. It also does not
411 * include other punctuation, as this will be stripped later during parsing and
412 * is of no information value when parsing a number.
418 i18n.phonenumbers.PhoneNumberUtil.VALID_START_CHAR_PATTERN =
419 new RegExp('[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ +
420 i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']');
424 * Regular expression of characters typically used to start a second phone
425 * number for the purposes of parsing. This allows us to strip off parts of the
426 * number that are actually the start of another number, such as for:
427 * (530) 583-6985 x302/x2303 -> the second extension here makes this actually
428 * two phone numbers, (530) 583-6985 x302 and (530) 583-6985 x2303. We remove
429 * the second extension so that the first number is parsed correctly.
435 i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_ = /[\\\/] *x/;
439 * Regular expression of trailing characters that we want to remove. We remove
440 * all characters that are not alpha or numerical characters. The hash character
441 * is retained here, as it may signify the previous block was an extension.
447 i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_ =
448 new RegExp('[^' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ +
449 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ + '#]+$');
453 * We use this pattern to check if the phone number has at least three letters
454 * in it - if so, then we treat it as a number where some phone-number digits
455 * are represented by letters.
461 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_ =
462 /(?:.*?[A-Za-z]){3}.*/;
466 * Regular expression of viable phone numbers. This is location independent.
467 * Checks we have at least three leading digits, and only valid punctuation,
468 * alpha characters and digits in the phone number. Does not include extension
469 * data. The symbol 'x' is allowed here as valid punctuation since it is often
470 * used as a placeholder for carrier codes, for example in Brazilian phone
471 * numbers. We also allow multiple '+' characters at the start.
472 * Corresponds to the following:
473 * plus_sign*([punctuation]*[digits]){3,}([punctuation]|[digits]|[alpha])*
474 * Note VALID_PUNCTUATION starts with a -, so must be the first in the range.
480 i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ =
481 '[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']*(?:[' +
482 i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION_ + ']*[' +
483 i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']){3,}[' +
484 i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION_ +
485 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ +
486 i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']*';
490 * Default extension prefix to use when formatting. This will be put in front of
491 * any extension component of the number, after the main national number is
492 * formatted. For example, if you wish the default extension formatting to be
493 * ' extn: 3456', then you should specify ' extn: ' here as the default
494 * extension prefix. This can be overridden by country-specific preferences.
500 i18n.phonenumbers.PhoneNumberUtil.DEFAULT_EXTN_PREFIX_ = ' ext. ';
504 * Regexp of all possible ways to write extensions, for use when parsing. This
505 * will be run as a case-insensitive regexp match. Wide character versions are
506 * also provided after each ascii version. There are two regular expressions
507 * here: the more generic one starts with optional white space and ends with an
508 * optional full stop (.), followed by zero or more spaces/tabs and then the
509 * numbers themselves. The other one covers the special case of American numbers
510 * where the extension is written with a hash at the end, such as "- 503#". Note
511 * that the only capturing groups should be around the digits that you want to
512 * capture as part of the extension, or else parsing will fail! We allow two
513 * options for representing the accented o - the character itself, and one in
514 * the unicode decomposed form with the combining acute accent.
520 i18n.phonenumbers.PhoneNumberUtil.KNOWN_EXTN_PATTERNS_ =
522 '(?:ext(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45\uFF58\uFF54\uFF4E?|' +
523 '[,x\uFF58#\uFF03~\uFF5E]|int|anexo|\uFF49\uFF4E\uFF54)' +
524 '[:\\.\uFF0E]?[ \u00A0\\t,-]*([' +
525 i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{1,7})#?|[- ]+([' +
526 i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{1,5})#';
530 * Regexp of all known extension prefixes used by different countries followed
531 * by 1 or more valid digits, for use when parsing.
537 i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_ =
538 new RegExp('(?:' + i18n.phonenumbers.PhoneNumberUtil.KNOWN_EXTN_PATTERNS_ +
543 * We append optionally the extension pattern to the end here, as a valid phone
544 * number may have an extension prefix appended, followed by 1 or more digits.
550 i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_PATTERN_ =
551 new RegExp('^' + i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ +
552 '(?:' + i18n.phonenumbers.PhoneNumberUtil.KNOWN_EXTN_PATTERNS_ +
561 i18n.phonenumbers.PhoneNumberUtil.NON_DIGITS_PATTERN_ = /\D+/;
569 i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_ = /(\$1)/;
577 i18n.phonenumbers.PhoneNumberUtil.NP_PATTERN_ = /\$NP/;
585 i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_ = /\$FG/;
593 i18n.phonenumbers.PhoneNumberUtil.CC_PATTERN_ = /\$CC/;
597 * INTERNATIONAL and NATIONAL formats are consistent with the definition in
598 * ITU-T Recommendation E. 123. For example, the number of the Google Zurich
599 * office will be written as "+41 44 668 1800" in INTERNATIONAL format, and as
600 * "044 668 1800" in NATIONAL format. E164 format is as per INTERNATIONAL format
601 * but with no formatting applied, e.g. +41446681800.
605 i18n.phonenumbers.PhoneNumberFormat = {
613 * Type of phone numbers.
617 i18n.phonenumbers.PhoneNumberType = {
620 // In some countries (e.g. the USA), it is impossible to distinguish between
621 // fixed-line and mobile numbers by looking at the phone number itself.
622 FIXED_LINE_OR_MOBILE: 2,
626 // The cost of this call is shared between the caller and the recipient, and
627 // is hence typically less than PREMIUM_RATE calls. See
628 // http://en.wikipedia.org/wiki/Shared_Cost_Service for more information.
630 // Voice over IP numbers. This includes TSoIP (Telephony Service over IP).
632 // A personal number is associated with a particular person, and may be routed
633 // to either a MOBILE or FIXED_LINE number. Some more information can be found
634 // here: http://en.wikipedia.org/wiki/Personal_Numbers
637 // Used for "Universal Access Numbers" or "Company Numbers". They may be
638 // further routed to specific offices, but allow one number to be used for a
641 // A phone number is of type UNKNOWN when it does not fit any of the known
642 // patterns for a specific country.
648 * Types of phone number matches. See detailed description beside the
649 * isNumberMatch() method.
653 i18n.phonenumbers.PhoneNumberUtil.MatchType = {
663 * Possible outcomes when testing if a PhoneNumber is possible.
667 i18n.phonenumbers.PhoneNumberUtil.ValidationResult = {
669 INVALID_COUNTRY_CODE: 1,
676 * Attempts to extract a possible number from the string passed in. This
677 * currently strips all leading characters that could not be used to start a
678 * phone number. Characters that can be used to start a phone number are defined
679 * in the VALID_START_CHAR_PATTERN. If none of these characters are found in the
680 * number passed in, an empty string is returned. This function also attempts to
681 * strip off any alternative extensions or endings if two or more are present,
682 * such as in the case of: (530) 583-6985 x302/x2303. The second extension here
683 * makes this actually two phone numbers, (530) 583-6985 x302 and (530) 583-6985
684 * x2303. We remove the second extension so that the first number is parsed
687 * @param {string} number the string that might contain a phone number.
688 * @return {string} the number, stripped of any non-phone-number prefix (such as
689 * 'Tel:') or an empty string if no character used to start phone numbers
690 * (such as + or any digit) is found in the number.
692 i18n.phonenumbers.PhoneNumberUtil.extractPossibleNumber = function(number) {
693 /** @type {string} */
696 /** @type {number} */
698 .search(i18n.phonenumbers.PhoneNumberUtil.VALID_START_CHAR_PATTERN);
700 possibleNumber = number.substring(start);
701 // Remove trailing non-alpha non-numerical characters.
702 possibleNumber = possibleNumber.replace(
703 i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_, '');
705 // Check for extra numbers at the end.
706 /** @type {number} */
707 var secondNumberStart = possibleNumber
708 .search(i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_);
709 if (secondNumberStart >= 0) {
710 possibleNumber = possibleNumber.substring(0, secondNumberStart);
715 return possibleNumber;
720 * Checks to see if the string of characters could possibly be a phone number at
721 * all. At the moment, checks to see that the string begins with at least 3
722 * digits, ignoring any punctuation commonly found in phone numbers. This method
723 * does not require the number to be normalized in advance - but does assume
724 * that leading non-number symbols have been removed, such as by the method
725 * extractPossibleNumber.
727 * @param {string} number string to be checked for viability as a phone number.
728 * @return {boolean} true if the number could be a phone number of some sort,
731 i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber = function(number) {
732 if (number.length < i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
735 return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
736 i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_PATTERN_, number);
741 * Normalizes a string of characters representing a phone number. This performs
742 * the following conversions:
743 * - Wide-ascii digits are converted to normal ASCII (European) digits.
744 * - Letters are converted to their numeric representation on a telephone
745 * keypad. The keypad used here is the one defined in ITU Recommendation E.161.
746 * This is only done if there are 3 or more letters in the number, to lessen the
747 * risk that such letters are typos - otherwise alpha characters are stripped.
748 * - Punctuation is stripped.
749 * - Arabic-Indic numerals are converted to European numerals.
751 * @param {string} number a string of characters representing a phone number.
752 * @return {string} the normalized string version of the phone number.
754 i18n.phonenumbers.PhoneNumberUtil.normalize = function(number) {
755 if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
756 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_, number)) {
757 return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
758 i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_, true);
760 return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
761 i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS, true);
767 * Normalizes a string of characters representing a phone number. This is a
768 * wrapper for normalize(String number) but does in-place normalization of the
769 * StringBuffer provided.
771 * @param {!goog.string.StringBuffer} number a StringBuffer of characters
772 * representing a phone number that will be normalized in place.
775 i18n.phonenumbers.PhoneNumberUtil.normalizeSB_ = function(number) {
776 /** @type {string} */
777 var normalizedNumber = i18n.phonenumbers.PhoneNumberUtil.normalize(number
780 number.append(normalizedNumber);
785 * Normalizes a string of characters representing a phone number. This converts
786 * wide-ascii and arabic-indic numerals to European numerals, and strips
787 * punctuation and alpha characters.
789 * @param {string} number a string of characters representing a phone number.
790 * @return {string} the normalized string version of the phone number.
792 i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly = function(number) {
793 return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
794 i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS, true);
799 * Converts all alpha characters in a number to their respective digits on a
800 * keypad, but retains existing formatting. Also converts wide-ascii digits to
801 * normal ascii digits, and converts Arabic-Indic numerals to European numerals.
803 * @param {string} number a string of characters representing a phone number.
804 * @return {string} the normalized string version of the phone number.
806 i18n.phonenumbers.PhoneNumberUtil.convertAlphaCharactersInNumber =
809 return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
810 i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_, false);
815 * Gets the length of the geographical area code from the national_number field
816 * of the PhoneNumber object passed in, so that clients could use it to split a
817 * national significant number into geographical area code and subscriber
818 * number. It works in such a way that the resultant subscriber number should be
819 * diallable, at least on some devices. An example of how this could be used:
821 * var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
822 * var number = phoneUtil.parse('16502530000', 'US');
823 * var nationalSignificantNumber =
824 * i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
826 * var subscriberNumber;
828 * var areaCodeLength = phoneUtil.getLengthOfGeographicalAreaCode(number);
829 * if (areaCodeLength > 0) {
830 * areaCode = nationalSignificantNumber.substring(0, areaCodeLength);
831 * subscriberNumber = nationalSignificantNumber.substring(areaCodeLength);
834 * subscriberNumber = nationalSignificantNumber;
837 * N.B.: area code is a very ambiguous concept, so the I18N team generally
838 * recommends against using it for most purposes, but recommends using the more
839 * general national_number instead. Read the following carefully before deciding
840 * to use this method:
841 * - geographical area codes change over time, and this method honors those
842 * changes; therefore, it doesn't guarantee the stability of the result it
844 * - subscriber numbers may not be diallable from all devices (notably mobile
845 * devices, which typically requires the full national_number to be dialled in
847 * - most non-geographical numbers have no area codes.
848 * - some geographical numbers have no area codes.
850 * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
851 * which clients want to know the length of the area code in the
852 * national_number field.
853 * @return {number} the length of area code of the PhoneNumber object passed in.
855 i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfGeographicalAreaCode =
858 if (number == null) {
861 /** @type {?string} */
862 var regionCode = this.getRegionCodeForNumber(number);
863 if (!this.isValidRegionCode_(regionCode)) {
866 /** @type {i18n.phonenumbers.PhoneMetadata} */
867 var metadata = this.getMetadataForRegion(regionCode);
868 if (!metadata.hasNationalPrefix()) {
872 /** @type {i18n.phonenumbers.PhoneNumberType} */
873 var type = this.getNumberTypeHelper_(
874 i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number),
876 // Most numbers other than the two types below have to be dialled in full.
877 if (type != i18n.phonenumbers.PhoneNumberType.FIXED_LINE &&
878 type != i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE) {
882 return this.getLengthOfNationalDestinationCode(number);
887 * Gets the length of the national destination code (NDC) from the PhoneNumber
888 * object passed in, so that clients could use it to split a national
889 * significant number into NDC and subscriber number. The NDC of a phone number
890 * is normally the first group of digit(s) right after the country code when the
891 * number is formatted in the international format, if there is a subscriber
892 * number part that follows. An example of how this could be used:
894 * var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
895 * var number = phoneUtil.parse('18002530000', 'US');
896 * var nationalSignificantNumber =
897 * i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
898 * var nationalDestinationCode;
899 * var subscriberNumber;
901 * var nationalDestinationCodeLength =
902 * phoneUtil.getLengthOfNationalDestinationCode(number);
903 * if (nationalDestinationCodeLength > 0) {
904 * nationalDestinationCode =
905 * nationalSignificantNumber.substring(0, nationalDestinationCodeLength);
907 * nationalSignificantNumber.substring(nationalDestinationCodeLength);
909 * nationalDestinationCode = '';
910 * subscriberNumber = nationalSignificantNumber;
913 * Refer to the unittests to see the difference between this function and
914 * getLengthOfGeographicalAreaCode().
916 * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
917 * which clients want to know the length of the NDC.
918 * @return {number} the length of NDC of the PhoneNumber object passed in.
920 i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfNationalDestinationCode =
923 /** @type {i18n.phonenumbers.PhoneNumber} */
925 if (number.hasExtension()) {
926 // We don't want to alter the proto given to us, but we don't want to
927 // include the extension when we format it, so we copy it and clear the
929 copiedProto = new i18n.phonenumbers.PhoneNumber();
930 copiedProto.mergeFrom(number);
931 copiedProto.clearExtension();
933 copiedProto = number;
936 /** @type {string} */
937 var nationalSignificantNumber = this.format(copiedProto,
938 i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
939 /** @type {!Array.<string>} */
940 var numberGroups = nationalSignificantNumber.split(
941 i18n.phonenumbers.PhoneNumberUtil.NON_DIGITS_PATTERN_);
942 // The pattern will start with '+COUNTRY_CODE ' so the first group will always
943 // be the empty string (before the + symbol) and the second group will be the
944 // country code. The third group will be area code if it's not the last group.
945 // NOTE: On IE the first group that is supposed to be the empty string does
946 // not appear in the array of number groups... so make the result on non-IE
947 // browsers to be that of IE.
948 if (numberGroups[0].length == 0) {
949 numberGroups.shift();
951 if (numberGroups.length <= 2) {
955 if (this.getRegionCodeForNumber(number) == 'AR' &&
956 this.getNumberType(number) == i18n.phonenumbers.PhoneNumberType.MOBILE) {
957 // Argentinian mobile numbers, when formatted in the international format,
958 // are in the form of +54 9 NDC XXXX.... As a result, we take the length of
959 // the third group (NDC) and add 1 for the digit 9, which also forms part of
960 // the national significant number.
962 // TODO: Investigate the possibility of better modeling the metadata to make
963 // it easier to obtain the NDC.
964 return numberGroups[2].length + 1;
966 return numberGroups[1].length;
971 * Normalizes a string of characters representing a phone number by replacing
972 * all characters found in the accompanying map with the values therein, and
973 * stripping all other characters if removeNonMatches is true.
975 * @param {string} number a string of characters representing a phone number.
976 * @param {!Object} normalizationReplacements a mapping of characters to what
977 * they should be replaced by in the normalized version of the phone number.
978 * @param {boolean} removeNonMatches indicates whether characters that are not
979 * able to be replaced should be stripped from the number. If this is false,
980 * they will be left unchanged in the number.
981 * @return {string} the normalized string version of the phone number.
984 i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_ =
985 function(number, normalizationReplacements, removeNonMatches) {
987 /** @type {!goog.string.StringBuffer} */
988 var normalizedNumber = new goog.string.StringBuffer();
989 /** @type {string} */
991 /** @type {string} */
993 /** @type {number} */
994 var numberLength = number.length;
995 for (var i = 0; i < numberLength; ++i) {
996 character = number.charAt(i);
997 newDigit = normalizationReplacements[character.toUpperCase()];
998 if (newDigit != null) {
999 normalizedNumber.append(newDigit);
1000 } else if (!removeNonMatches) {
1001 normalizedNumber.append(character);
1003 // If neither of the above are true, we remove this character.
1005 return normalizedNumber.toString();
1010 * Helper function to check region code is not unknown or null.
1012 * @param {?string} regionCode the ISO 3166-1 two-letter country code that
1013 * denotes the country/region that we want to get the country code for.
1014 * @return {boolean} true if region code is valid.
1017 i18n.phonenumbers.PhoneNumberUtil.prototype.isValidRegionCode_ =
1018 function(regionCode) {
1020 return regionCode != null &&
1021 regionCode.toUpperCase() in i18n.phonenumbers.metadata.countryToMetadata;
1026 * Formats a phone number in the specified format using default rules. Note that
1027 * this does not promise to produce a phone number that the user can dial from
1028 * where they are - although we do format in either 'national' or
1029 * 'international' format depending on what the client asks for, we do not
1030 * currently support a more abbreviated format, such as for users in the same
1031 * "area" who could potentially dial the number without area code. Note that if
1032 * the phone number has a country code of 0 or an otherwise invalid country
1033 * code, we cannot work out which formatting rules to apply so we return the
1034 * national significant number with no formatting applied.
1036 * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
1038 * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
1039 * phone number should be formatted into.
1040 * @return {string} the formatted phone number.
1042 i18n.phonenumbers.PhoneNumberUtil.prototype.format =
1043 function(number, numberFormat) {
1045 /** @type {number} */
1046 var countryCode = number.getCountryCodeOrDefault();
1047 /** @type {string} */
1048 var nationalSignificantNumber = i18n.phonenumbers.PhoneNumberUtil
1049 .getNationalSignificantNumber(number);
1050 if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.E164) {
1051 // Early exit for E164 case since no formatting of the national number needs
1052 // to be applied. Extensions are not formatted.
1053 return this.formatNumberByFormat_(countryCode,
1054 i18n.phonenumbers.PhoneNumberFormat.E164,
1055 nationalSignificantNumber, '');
1057 // Note getRegionCodeForCountryCode() is used because formatting information
1058 // for countries which share a country code is contained by only one country
1059 // for performance reasons. For example, for NANPA countries it will be
1060 // contained in the metadata for US.
1061 /** @type {string} */
1062 var regionCode = this.getRegionCodeForCountryCode(countryCode);
1063 if (!this.isValidRegionCode_(regionCode)) {
1064 return nationalSignificantNumber;
1067 /** @type {string} */
1068 var formattedExtension = this.maybeGetFormattedExtension_(number, regionCode);
1069 /** @type {string} */
1070 var formattedNationalNumber =
1071 this.formatNationalNumber_(nationalSignificantNumber,
1074 return this.formatNumberByFormat_(countryCode,
1076 formattedNationalNumber,
1077 formattedExtension);
1082 * Formats a phone number in the specified format using client-defined
1083 * formatting rules. Note that if the phone number has a country code of zero or
1084 * an otherwise invalid country code, we cannot work out things like whether
1085 * there should be a national prefix applied, or how to format extensions, so we
1086 * return the national significant number with no formatting applied.
1088 * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
1090 * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
1091 * phone number should be formatted into.
1092 * @param {Array.<i18n.phonenumbers.NumberFormat>} userDefinedFormats formatting
1093 * rules specified by clients.
1094 * @return {string} the formatted phone number.
1096 i18n.phonenumbers.PhoneNumberUtil.prototype.formatByPattern =
1097 function(number, numberFormat, userDefinedFormats) {
1099 /** @type {number} */
1100 var countryCode = number.getCountryCodeOrDefault();
1101 /** @type {string} */
1102 var nationalSignificantNumber =
1103 i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
1104 // Note getRegionCodeForCountryCode() is used because formatting information
1105 // for countries which share a country code is contained by only one country
1106 // for performance reasons. For example, for NANPA countries it will be
1107 // contained in the metadata for US.
1108 /** @type {string} */
1109 var regionCode = this.getRegionCodeForCountryCode(countryCode);
1110 if (!this.isValidRegionCode_(regionCode)) {
1111 return nationalSignificantNumber;
1113 /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
1114 var userDefinedFormatsCopy = [];
1115 /** @type {number} */
1116 var size = userDefinedFormats.length;
1117 for (var i = 0; i < size; ++i) {
1118 /** @type {i18n.phonenumbers.NumberFormat} */
1119 var numFormat = userDefinedFormats[i];
1120 /** @type {string} */
1121 var nationalPrefixFormattingRule =
1122 numFormat.getNationalPrefixFormattingRuleOrDefault();
1123 if (nationalPrefixFormattingRule.length > 0) {
1124 // Before we do a replacement of the national prefix pattern $NP with the
1125 // national prefix, we need to copy the rule so that subsequent
1126 // replacements for different numbers have the appropriate national
1128 /** type {i18n.phonenumbers.NumberFormat} */
1129 var numFormatCopy = new i18n.phonenumbers.NumberFormat();
1130 numFormatCopy.mergeFrom(numFormat);
1131 /** @type {string} */
1132 var nationalPrefix =
1133 this.getMetadataForRegion(regionCode).getNationalPrefixOrDefault();
1134 if (nationalPrefix.length > 0) {
1135 // Replace $NP with national prefix and $FG with the first group ($1).
1136 nationalPrefixFormattingRule = nationalPrefixFormattingRule
1137 .replace(i18n.phonenumbers.PhoneNumberUtil.NP_PATTERN_,
1139 .replace(i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_, '$1');
1140 numFormatCopy.setNationalPrefixFormattingRule(
1141 nationalPrefixFormattingRule);
1143 // We don't want to have a rule for how to format the national prefix if
1145 numFormatCopy.clearNationalPrefixFormattingRule();
1147 userDefinedFormatsCopy.push(numFormatCopy);
1149 // Otherwise, we just add the original rule to the modified list of
1151 userDefinedFormatsCopy.push(numFormat);
1155 /** @type {string} */
1156 var formattedExtension = this.maybeGetFormattedExtension_(number, regionCode);
1157 /** @type {string} */
1158 var formattedNationalNumber =
1159 this.formatAccordingToFormats_(nationalSignificantNumber,
1160 userDefinedFormatsCopy,
1162 return this.formatNumberByFormat_(countryCode,
1164 formattedNationalNumber,
1165 formattedExtension);
1170 * @param {i18n.phonenumbers.PhoneNumber} number
1171 * @param {string} carrierCode
1174 i18n.phonenumbers.PhoneNumberUtil.prototype.
1175 formatNationalNumberWithCarrierCode = function(number, carrierCode) {
1177 /** @type {number} */
1178 var countryCode = number.getCountryCodeOrDefault();
1179 /** @type {string} */
1180 var nationalSignificantNumber =
1181 i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
1182 // Note getRegionCodeForCountryCode() is used because formatting information
1183 // for countries which share a country code is contained by only one country
1184 // for performance reasons. For example, for NANPA countries it will be
1185 // contained in the metadata for US.
1186 /** @type {string} */
1187 var regionCode = this.getRegionCodeForCountryCode(countryCode);
1188 if (!this.isValidRegionCode_(regionCode)) {
1189 return nationalSignificantNumber;
1192 /** @type {string} */
1193 var formattedExtension = this.maybeGetFormattedExtension_(number, regionCode);
1194 /** @type {string} */
1195 var formattedNationalNumber =
1196 this.formatNationalNumber_(nationalSignificantNumber,
1198 i18n.phonenumbers.PhoneNumberFormat.NATIONAL,
1200 return this.formatNumberByFormat_(
1201 countryCode, i18n.phonenumbers.PhoneNumberFormat.NATIONAL,
1202 formattedNationalNumber, formattedExtension);
1207 * Formats a phone number for out-of-country dialing purpose. If no
1208 * countryCallingFrom is supplied, we format the number in its INTERNATIONAL
1209 * format. If the countryCallingFrom is the same as the country where the number
1210 * is from, then NATIONAL formatting will be applied.
1212 * If the number itself has a country code of zero or an otherwise invalid
1213 * country code, then we return the number with no formatting applied.
1215 * Note this function takes care of the case for calling inside of NANPA and
1216 * between Russia and Kazakhstan (who share the same country code). In those
1217 * cases, no international prefix is used. For countries which have multiple
1218 * international prefixes, the number in its INTERNATIONAL format will be
1221 * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
1223 * @param {string} countryCallingFrom the ISO 3166-1 two-letter country code
1224 * that denotes the foreign country where the call is being placed.
1225 * @return {string} the formatted phone number.
1227 i18n.phonenumbers.PhoneNumberUtil.prototype.formatOutOfCountryCallingNumber =
1228 function(number, countryCallingFrom) {
1230 if (!this.isValidRegionCode_(countryCallingFrom)) {
1231 return this.format(number,
1232 i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
1234 /** @type {number} */
1235 var countryCode = number.getCountryCodeOrDefault();
1236 /** @type {string} */
1237 var regionCode = this.getRegionCodeForCountryCode(countryCode);
1238 /** @type {string} */
1239 var nationalSignificantNumber =
1240 i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
1241 if (!this.isValidRegionCode_(regionCode)) {
1242 return nationalSignificantNumber;
1244 if (countryCode == i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_) {
1245 if (this.isNANPACountry(countryCallingFrom)) {
1246 // For NANPA countries, return the national format for these countries but
1247 // prefix it with the country code.
1248 return countryCode + ' ' +
1249 this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1251 } else if (countryCode == this.getCountryCodeForRegion(countryCallingFrom)) {
1252 // For countries that share a country calling code, the country code need
1253 // not be dialled. This also applies when dialling within a country, so this
1254 // if clause covers both these cases. Technically this is the case for
1255 // dialling from la Reunion to other overseas departments of France (French
1256 // Guiana, Martinique, Guadeloupe), but not vice versa - so we don't cover
1257 // this edge case for now and for those cases return the version including
1258 // country code. Details here:
1259 // http://www.petitfute.com/voyage/225-info-pratiques-reunion
1260 return this.format(number,
1261 i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1263 /** @type {string} */
1264 var formattedNationalNumber =
1265 this.formatNationalNumber_(nationalSignificantNumber, regionCode,
1266 i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
1267 /** @type {i18n.phonenumbers.PhoneMetadata} */
1268 var metadata = this.getMetadataForRegion(countryCallingFrom);
1269 /** @type {string} */
1270 var internationalPrefix = metadata.getInternationalPrefixOrDefault();
1271 /** @type {string} */
1272 var formattedExtension = this.maybeGetFormattedExtension_(number, regionCode);
1274 // For countries that have multiple international prefixes, the international
1275 // format of the number is returned, unless there is a preferred international
1277 /** @type {string} */
1278 var internationalPrefixForFormatting = '';
1279 if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
1280 i18n.phonenumbers.PhoneNumberUtil.UNIQUE_INTERNATIONAL_PREFIX_,
1281 internationalPrefix)) {
1282 internationalPrefixForFormatting = internationalPrefix;
1283 } else if (metadata.hasPreferredInternationalPrefix()) {
1284 internationalPrefixForFormatting =
1285 metadata.getPreferredInternationalPrefixOrDefault();
1288 return internationalPrefixForFormatting != '' ?
1289 internationalPrefixForFormatting + ' ' + countryCode + ' ' +
1290 formattedNationalNumber + formattedExtension :
1291 this.formatNumberByFormat_(
1292 countryCode, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL,
1293 formattedNationalNumber, formattedExtension);
1298 * Formats a phone number using the original phone number format that the number
1299 * is parsed from. The original format is embedded in the country_code_source
1300 * field of the PhoneNumber object passed in. If such information is missing,
1301 * the number will be formatted into the NATIONAL format by default.
1303 * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber that needs to
1304 * be formatted in its original number format.
1305 * @param {string} countryCallingFrom the country whose IDD needs to be prefixed
1306 * if the original number has one.
1307 * @return {string} the formatted phone number in its original number format.
1309 i18n.phonenumbers.PhoneNumberUtil.prototype.formatInOriginalFormat =
1310 function(number, countryCallingFrom) {
1312 if (!number.hasCountryCodeSource()) {
1313 return this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1315 switch (number.getCountryCodeSource()) {
1316 case i18n.phonenumbers.PhoneNumber.CountryCodeSource
1317 .FROM_NUMBER_WITH_PLUS_SIGN:
1318 return this.format(number,
1319 i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
1320 case i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD:
1321 return this.formatOutOfCountryCallingNumber(number, countryCallingFrom);
1322 case i18n.phonenumbers.PhoneNumber.CountryCodeSource
1323 .FROM_NUMBER_WITHOUT_PLUS_SIGN:
1324 return this.format(number,
1325 i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL).substring(1);
1326 case i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY:
1328 return this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1334 * Gets the national significant number of the a phone number. Note a national
1335 * significant number doesn't contain a national prefix or any formatting.
1337 * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
1338 * which the national significant number is needed.
1339 * @return {string} the national significant number of the PhoneNumber object
1342 i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber =
1345 // The leading zero in the national (significant) number of an Italian phone
1346 // number has a special meaning. Unlike the rest of the world, it indicates
1347 // the number is a landline number. There have been plans to migrate landline
1348 // numbers to start with the digit two since December 2000, but it has not yet
1349 // happened. See http://en.wikipedia.org/wiki/%2B39 for more details.
1350 // Other countries such as Cote d'Ivoire and Gabon use this for their mobile
1352 /** @type {string} */
1353 var nationalNumber = '' + number.getNationalNumber();
1354 if (number.hasItalianLeadingZero() && number.getItalianLeadingZero() &&
1355 i18n.phonenumbers.PhoneNumberUtil.isLeadingZeroCountry(
1356 number.getCountryCodeOrDefault())) {
1357 return '0' + nationalNumber;
1359 return nationalNumber;
1364 * A helper function that is used by format and formatByPattern.
1366 * @param {number} countryCode the country calling code.
1367 * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
1368 * phone number should be formatted into.
1369 * @param {string} formattedNationalNumber
1370 * @param {string} formattedExtension
1371 * @return {string} the formatted phone number.
1374 i18n.phonenumbers.PhoneNumberUtil.prototype.formatNumberByFormat_ =
1375 function(countryCode, numberFormat,
1376 formattedNationalNumber, formattedExtension) {
1378 switch (numberFormat) {
1379 case i18n.phonenumbers.PhoneNumberFormat.E164:
1380 return i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCode +
1381 formattedNationalNumber + formattedExtension;
1382 case i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL:
1383 return i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCode + ' ' +
1384 formattedNationalNumber + formattedExtension;
1385 case i18n.phonenumbers.PhoneNumberFormat.NATIONAL:
1387 return formattedNationalNumber + formattedExtension;
1393 * Note in some countries, the national number can be written in two completely
1394 * different ways depending on whether it forms part of the NATIONAL format or
1395 * INTERNATIONAL format. The numberFormat parameter here is used to specify
1396 * which format to use for those cases. If a carrierCode is specified, this will
1397 * be inserted into the formatted string to replace $CC.
1399 * @param {string} number a string of characters representing a phone number.
1400 * @param {string} regionCode the ISO 3166-1 two-letter country code.
1401 * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
1402 * phone number should be formatted into.
1403 * @param {string=} opt_carrierCode
1404 * @return {string} the formatted phone number.
1407 i18n.phonenumbers.PhoneNumberUtil.prototype.formatNationalNumber_ =
1408 function(number, regionCode, numberFormat, opt_carrierCode) {
1410 /** @type {i18n.phonenumbers.PhoneMetadata} */
1411 var metadata = this.getMetadataForRegion(regionCode);
1412 /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
1413 var intlNumberFormats = metadata.intlNumberFormatArray();
1414 // When the intlNumberFormats exists, we use that to format national number
1415 // for the INTERNATIONAL format instead of using the numberDesc.numberFormats.
1416 /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
1417 var availableFormats =
1418 (intlNumberFormats.length == 0 ||
1419 numberFormat == i18n.phonenumbers.PhoneNumberFormat.NATIONAL) ?
1420 metadata.numberFormatArray() : metadata.intlNumberFormatArray();
1421 return this.formatAccordingToFormats_(number, availableFormats, numberFormat,
1427 * Note that carrierCode is optional - if NULL or an empty string, no carrier
1428 * code replacement will take place. Carrier code replacement occurs before
1429 * national prefix replacement.
1431 * @param {string} nationalNumber a string of characters representing a phone
1433 * @param {Array.<i18n.phonenumbers.NumberFormat>} availableFormats the
1434 * available formats the phone number could be formatted into.
1435 * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
1436 * phone number should be formatted into.
1437 * @param {string=} opt_carrierCode
1438 * @return {string} the formatted phone number.
1441 i18n.phonenumbers.PhoneNumberUtil.prototype.formatAccordingToFormats_ =
1442 function(nationalNumber, availableFormats, numberFormat, opt_carrierCode) {
1444 /** @type {i18n.phonenumbers.NumberFormat} */
1446 /** @type {number} */
1447 var l = availableFormats.length;
1448 for (var i = 0; i < l; ++i) {
1449 numFormat = availableFormats[i];
1450 /** @type {number} */
1451 var size = numFormat.leadingDigitsPatternCount();
1453 // We always use the last leading_digits_pattern, as it is the most
1456 .search(numFormat.getLeadingDigitsPattern(size - 1)) == 0) {
1457 /** @type {RegExp} */
1458 var patternToMatch = new RegExp(numFormat.getPattern());
1459 /** @type {string} */
1460 var numberFormatRule = numFormat.getFormatOrDefault();
1461 if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(patternToMatch,
1463 if (opt_carrierCode != null && opt_carrierCode.length > 0) {
1464 /** @type {string} */
1465 var domesticCarrierCodeFormattingRule =
1466 numFormat.getDomesticCarrierCodeFormattingRuleOrDefault();
1467 if (domesticCarrierCodeFormattingRule.length > 0) {
1468 // Replace the $CC in the formatting rule with the desired carrier
1470 /** @type {string} */
1471 var carrierCodeFormattingRule = domesticCarrierCodeFormattingRule
1472 .replace(i18n.phonenumbers.PhoneNumberUtil.CC_PATTERN_,
1474 // Now replace the $FG in the formatting rule with the first group
1475 // and the carrier code combined in the appropriate way.
1476 numberFormatRule = numberFormatRule.replace(
1477 i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_,
1478 carrierCodeFormattingRule);
1481 /** @type {string} */
1482 var nationalPrefixFormattingRule =
1483 numFormat.getNationalPrefixFormattingRuleOrDefault();
1484 if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.NATIONAL &&
1485 nationalPrefixFormattingRule != null &&
1486 nationalPrefixFormattingRule.length > 0) {
1487 return nationalNumber.replace(patternToMatch, numberFormatRule
1488 .replace(i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_,
1489 nationalPrefixFormattingRule));
1491 return nationalNumber.replace(patternToMatch, numberFormatRule);
1497 // If no pattern above is matched, we format the number as a whole.
1498 return nationalNumber;
1503 * Gets a valid number for the specified country.
1505 * @param {string} regionCode the ISO 3166-1 two-letter country code that
1506 * denotes the country for which an example number is needed.
1507 * @return {i18n.phonenumbers.PhoneNumber} a valid fixed-line number for the
1508 * specified country. Returns null when the metadata does not contain such
1511 i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumber =
1512 function(regionCode) {
1514 return this.getExampleNumberForType(regionCode,
1515 i18n.phonenumbers.PhoneNumberType.FIXED_LINE);
1520 * Gets a valid number, if any, for the specified country and number type.
1522 * @param {string} regionCode the ISO 3166-1 two-letter country code that
1523 * denotes the country for which an example number is needed.
1524 * @param {i18n.phonenumbers.PhoneNumberType} type the type of number that is
1526 * @return {i18n.phonenumbers.PhoneNumber} a valid number for the specified
1527 * country and type. Returns null when the metadata does not contain such
1530 i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumberForType =
1531 function(regionCode, type) {
1533 /** @type {i18n.phonenumbers.PhoneNumberDesc} */
1534 var desc = this.getNumberDescByType_(
1535 this.getMetadataForRegion(regionCode), type);
1537 if (desc.hasExampleNumber()) {
1538 return this.parse(desc.getExampleNumberOrDefault(), regionCode);
1547 * Gets the formatted extension of a phone number, if the phone number had an
1548 * extension specified. If not, it returns an empty string.
1550 * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber that might have
1552 * @param {string} regionCode the ISO 3166-1 two-letter country code.
1553 * @return {string} the formatted extension if any.
1556 i18n.phonenumbers.PhoneNumberUtil.prototype.maybeGetFormattedExtension_ =
1557 function(number, regionCode) {
1559 if (!number.hasExtension()) {
1562 return this.formatExtension_(number.getExtensionOrDefault(), regionCode);
1568 * Formats the extension part of the phone number by prefixing it with the
1569 * appropriate extension prefix. This will be the default extension prefix,
1570 * unless overridden by a preferred extension prefix for this country.
1572 * @param {string} extensionDigits the extension digits.
1573 * @param {string} regionCode the ISO 3166-1 two-letter country code.
1574 * @return {string} the formatted extension.
1577 i18n.phonenumbers.PhoneNumberUtil.prototype.formatExtension_ =
1578 function(extensionDigits, regionCode) {
1580 /** @type {i18n.phonenumbers.PhoneMetadata} */
1581 var metadata = this.getMetadataForRegion(regionCode);
1582 if (metadata.hasPreferredExtnPrefix()) {
1583 return metadata.getPreferredExtnPrefix() + extensionDigits;
1585 return i18n.phonenumbers.PhoneNumberUtil.DEFAULT_EXTN_PREFIX_ +
1592 * @param {i18n.phonenumbers.PhoneMetadata} metadata
1593 * @param {i18n.phonenumbers.PhoneNumberType} type
1594 * @return {i18n.phonenumbers.PhoneNumberDesc}
1597 i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberDescByType_ =
1598 function(metadata, type) {
1601 case i18n.phonenumbers.PhoneNumberType.PREMIUM_RATE:
1602 return metadata.getPremiumRate();
1603 case i18n.phonenumbers.PhoneNumberType.TOLL_FREE:
1604 return metadata.getTollFree();
1605 case i18n.phonenumbers.PhoneNumberType.MOBILE:
1606 return metadata.getMobile();
1607 case i18n.phonenumbers.PhoneNumberType.FIXED_LINE:
1608 case i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE:
1609 return metadata.getFixedLine();
1610 case i18n.phonenumbers.PhoneNumberType.SHARED_COST:
1611 return metadata.getSharedCost();
1612 case i18n.phonenumbers.PhoneNumberType.VOIP:
1613 return metadata.getVoip();
1614 case i18n.phonenumbers.PhoneNumberType.PERSONAL_NUMBER:
1615 return metadata.getPersonalNumber();
1616 case i18n.phonenumbers.PhoneNumberType.PAGER:
1617 return metadata.getPager();
1618 case i18n.phonenumbers.PhoneNumberType.UAN:
1619 return metadata.getUan();
1621 return metadata.getGeneralDesc();
1627 * Gets the type of a phone number.
1629 * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
1631 * @return {i18n.phonenumbers.PhoneNumberType} the type of the phone number.
1633 i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberType =
1636 /** @type {?string} */
1637 var regionCode = this.getRegionCodeForNumber(number);
1638 if (!this.isValidRegionCode_(regionCode)) {
1639 return i18n.phonenumbers.PhoneNumberType.UNKNOWN;
1641 /** @type {string} */
1642 var nationalSignificantNumber =
1643 i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
1644 return this.getNumberTypeHelper_(nationalSignificantNumber,
1645 this.getMetadataForRegion(regionCode));
1650 * @param {string} nationalNumber
1651 * @param {i18n.phonenumbers.PhoneMetadata} metadata
1652 * @return {i18n.phonenumbers.PhoneNumberType}
1655 i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberTypeHelper_ =
1656 function(nationalNumber, metadata) {
1658 /** @type {i18n.phonenumbers.PhoneNumberDesc} */
1659 var generalNumberDesc = metadata.getGeneralDesc();
1660 if (!generalNumberDesc.hasNationalNumberPattern() ||
1661 !this.isNumberMatchingDesc_(nationalNumber, generalNumberDesc)) {
1662 return i18n.phonenumbers.PhoneNumberType.UNKNOWN;
1665 if (this.isNumberMatchingDesc_(nationalNumber, metadata.getPremiumRate())) {
1666 return i18n.phonenumbers.PhoneNumberType.PREMIUM_RATE;
1668 if (this.isNumberMatchingDesc_(nationalNumber, metadata.getTollFree())) {
1669 return i18n.phonenumbers.PhoneNumberType.TOLL_FREE;
1671 if (this.isNumberMatchingDesc_(nationalNumber, metadata.getSharedCost())) {
1672 return i18n.phonenumbers.PhoneNumberType.SHARED_COST;
1674 if (this.isNumberMatchingDesc_(nationalNumber, metadata.getVoip())) {
1675 return i18n.phonenumbers.PhoneNumberType.VOIP;
1677 if (this.isNumberMatchingDesc_(nationalNumber,
1678 metadata.getPersonalNumber())) {
1679 return i18n.phonenumbers.PhoneNumberType.PERSONAL_NUMBER;
1681 if (this.isNumberMatchingDesc_(nationalNumber, metadata.getPager())) {
1682 return i18n.phonenumbers.PhoneNumberType.PAGER;
1684 if (this.isNumberMatchingDesc_(nationalNumber, metadata.getUan())) {
1685 return i18n.phonenumbers.PhoneNumberType.UAN;
1688 /** @type {boolean} */
1689 var isFixedLine = this.isNumberMatchingDesc_(nationalNumber, metadata
1692 if (metadata.getSameMobileAndFixedLinePattern()) {
1693 return i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE;
1694 } else if (this.isNumberMatchingDesc_(nationalNumber,
1695 metadata.getMobile())) {
1696 return i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE;
1698 return i18n.phonenumbers.PhoneNumberType.FIXED_LINE;
1700 // Otherwise, test to see if the number is mobile. Only do this if certain
1701 // that the patterns for mobile and fixed line aren't the same.
1702 if (!metadata.getSameMobileAndFixedLinePattern() &&
1703 this.isNumberMatchingDesc_(nationalNumber, metadata.getMobile())) {
1704 return i18n.phonenumbers.PhoneNumberType.MOBILE;
1706 return i18n.phonenumbers.PhoneNumberType.UNKNOWN;
1711 * @param {?string} regionCode
1712 * @return {i18n.phonenumbers.PhoneMetadata}
1714 i18n.phonenumbers.PhoneNumberUtil.prototype.getMetadataForRegion =
1715 function(regionCode) {
1717 if (regionCode == null) {
1720 regionCode = regionCode.toUpperCase();
1721 /** @type {i18n.phonenumbers.PhoneMetadata} */
1722 var metadata = this.countryToMetadata[regionCode];
1723 if (metadata == null) {
1724 /** @type {goog.proto2.PbLiteSerializer} */
1725 var serializer = new goog.proto2.PbLiteSerializer();
1726 /** @type {Array} */
1727 var metadataSerialized =
1728 i18n.phonenumbers.metadata.countryToMetadata[regionCode];
1729 if (metadataSerialized == null) {
1732 metadata = /** @type {i18n.phonenumbers.PhoneMetadata} */ (
1733 serializer.deserialize(i18n.phonenumbers.PhoneMetadata.getDescriptor(),
1734 metadataSerialized));
1735 this.countryToMetadata[regionCode] = metadata;
1742 * @param {string} nationalNumber
1743 * @param {i18n.phonenumbers.PhoneNumberDesc} numberDesc
1747 i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberMatchingDesc_ =
1748 function(nationalNumber, numberDesc) {
1750 return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
1751 numberDesc.getPossibleNumberPattern(), nationalNumber) &&
1752 i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
1753 numberDesc.getNationalNumberPattern(), nationalNumber);
1758 * Tests whether a phone number matches a valid pattern. Note this doesn't
1759 * verify the number is actually in use, which is impossible to tell by just
1760 * looking at a number itself.
1762 * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
1764 * @return {boolean} a boolean that indicates whether the number is of a valid
1767 i18n.phonenumbers.PhoneNumberUtil.prototype.isValidNumber = function(number) {
1768 /** @type {?string} */
1769 var regionCode = this.getRegionCodeForNumber(number);
1770 return this.isValidRegionCode_(regionCode) &&
1771 this.isValidNumberForRegion(number, /** @type {string} */ (regionCode));
1776 * Tests whether a phone number is valid for a certain region. Note this doesn't
1777 * verify the number is actually in use, which is impossible to tell by just
1778 * looking at a number itself. If the country code is not the same as the
1779 * country code for the region, this immediately exits with false. After this,
1780 * the specific number pattern rules for the region are examined. This is useful
1781 * for determining for example whether a particular number is valid for Canada,
1782 * rather than just a valid NANPA number.
1784 * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
1786 * @param {string} regionCode the ISO 3166-1 two-letter country code that
1787 * denotes the region/country that we want to validate the phone number for.
1788 * @return {boolean} a boolean that indicates whether the number is of a valid
1791 i18n.phonenumbers.PhoneNumberUtil.prototype.isValidNumberForRegion =
1792 function(number, regionCode) {
1794 if (number.getCountryCodeOrDefault() !=
1795 this.getCountryCodeForRegion(regionCode)) {
1798 /** @type {i18n.phonenumbers.PhoneMetadata} */
1799 var metadata = this.getMetadataForRegion(regionCode);
1800 /** @type {i18n.phonenumbers.PhoneNumberDesc} */
1801 var generalNumDesc = metadata.getGeneralDesc();
1802 /** @type {string} */
1803 var nationalSignificantNumber =
1804 i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
1806 // For countries where we don't have metadata for PhoneNumberDesc, we treat
1807 // any number passed in as a valid number if its national significant number
1808 // is between the minimum and maximum lengths defined by ITU for a national
1809 // significant number.
1810 if (!generalNumDesc.hasNationalNumberPattern()) {
1811 /** @type {number} */
1812 var numberLength = nationalSignificantNumber.length;
1813 return numberLength >
1814 i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_ &&
1815 numberLength <= i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_;
1817 return this.getNumberTypeHelper_(nationalSignificantNumber, metadata) !=
1818 i18n.phonenumbers.PhoneNumberType.UNKNOWN;
1823 * Returns the country/region where a phone number is from. This could be used
1824 * for geo-coding in the country/region level.
1826 * @param {i18n.phonenumbers.PhoneNumber} number the phone number whose origin
1828 * @return {?string} the country/region where the phone number is from, or null
1829 * if no country matches this calling code.
1831 i18n.phonenumbers.PhoneNumberUtil.prototype.getRegionCodeForNumber =
1834 if (number == null) {
1837 /** @type {number} */
1838 var countryCode = number.getCountryCodeOrDefault();
1839 /** @type {Array.<string>} */
1841 i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[countryCode];
1842 if (regions == null) {
1845 if (regions.length == 1) {
1848 return this.getRegionCodeForNumberFromRegionList_(number, regions);
1854 * @param {i18n.phonenumbers.PhoneNumber} number
1855 * @param {Array.<string>} regionCodes
1859 i18n.phonenumbers.PhoneNumberUtil.prototype.
1860 getRegionCodeForNumberFromRegionList_ = function(number, regionCodes) {
1862 /** @type {string} */
1863 var nationalNumber = '' + number.getNationalNumber();
1864 /** @type {string} */
1866 /** @type {number} */
1867 var regionCodesLength = regionCodes.length;
1868 for (var i = 0; i < regionCodesLength; i++) {
1869 regionCode = regionCodes[i];
1870 // If leadingDigits is present, use this. Otherwise, do full validation.
1871 /** @type {i18n.phonenumbers.PhoneMetadata} */
1872 var metadata = this.getMetadataForRegion(regionCode);
1873 if (metadata.hasLeadingDigits()) {
1874 if (nationalNumber.search(metadata.getLeadingDigits()) == 0) {
1877 } else if (this.getNumberTypeHelper_(nationalNumber, metadata) !=
1878 i18n.phonenumbers.PhoneNumberType.UNKNOWN) {
1887 * Returns the region code that matches the specific country code. In the case
1888 * of no region code being found, ZZ will be returned. In the case of multiple
1889 * regions, the one designated in the metadata as the "main" country for this
1890 * calling code will be returned.
1892 * @param {number} countryCode the country calling code.
1895 i18n.phonenumbers.PhoneNumberUtil.prototype.getRegionCodeForCountryCode =
1896 function(countryCode) {
1898 /** @type {Array.<string>} */
1900 i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[countryCode];
1901 return regionCodes == null ?
1902 i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_ : regionCodes[0];
1907 * Returns the country calling code for a specific region. For example, this
1908 * would be 1 for the United States, and 64 for New Zealand.
1910 * @param {?string} regionCode the ISO 3166-1 two-letter country code that
1911 * denotes the country/region that we want to get the country code for.
1912 * @return {number} the country calling code for the country/region denoted by
1915 i18n.phonenumbers.PhoneNumberUtil.prototype.getCountryCodeForRegion =
1916 function(regionCode) {
1918 if (!this.isValidRegionCode_(regionCode)) {
1921 /** @type {i18n.phonenumbers.PhoneMetadata} */
1922 var metadata = this.getMetadataForRegion(regionCode);
1923 if (metadata == null) {
1926 return metadata.getCountryCodeOrDefault();
1931 * Returns the national dialling prefix for a specific region. For example, this
1932 * would be 1 for the United States, and 0 for New Zealand. Set stripNonDigits
1933 * to true to strip symbols like "~" (which indicates a wait for a dialling
1934 * tone) from the prefix returned. If no national prefix is present, we return
1937 * Warning: Do not use this method for do-your-own formatting - for some
1938 * countries, the national dialling prefix is used only for certain types of
1939 * numbers. Use the library's formatting functions to prefix the national prefix
1942 * @param {string} regionCode the ISO 3166-1 two-letter country code that
1943 * denotes the country/region that we want to get the dialling prefix for.
1944 * @param {boolean} stripNonDigits true to strip non-digits from the national
1946 * @return {?string} the dialling prefix for the country/region denoted by
1949 i18n.phonenumbers.PhoneNumberUtil.prototype.getNddPrefixForRegion = function(
1950 regionCode, stripNonDigits) {
1951 if (!this.isValidRegionCode_(regionCode)) {
1954 /** @type {i18n.phonenumbers.PhoneMetadata} */
1955 var metadata = this.getMetadataForRegion(regionCode);
1956 if (metadata == null) {
1959 /** @type {string} */
1960 var nationalPrefix = metadata.getNationalPrefixOrDefault();
1961 // If no national prefix was found, we return null.
1962 if (nationalPrefix.length == 0) {
1965 if (stripNonDigits) {
1966 // Note: if any other non-numeric symbols are ever used in national
1967 // prefixes, these would have to be removed here as well.
1968 nationalPrefix = nationalPrefix.replace('~', '');
1970 return nationalPrefix;
1975 * Check if a country is one of the countries under the North American Numbering
1976 * Plan Administration (NANPA).
1978 * @param {string} regionCode the ISO 3166-1 two-letter country code.
1979 * @return {boolean} true if regionCode is one of the countries under NANPA.
1981 i18n.phonenumbers.PhoneNumberUtil.prototype.isNANPACountry =
1982 function(regionCode) {
1984 return goog.array.contains(
1985 i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[
1986 i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_],
1987 regionCode.toUpperCase());
1992 * Check whether countryCode represents the country calling code from a country
1993 * whose national significant number could contain a leading zero. An example of
1994 * such a country is Italy.
1996 * @param {number} countryCode the country calling code.
1999 i18n.phonenumbers.PhoneNumberUtil.isLeadingZeroCountry = function(countryCode) {
2000 return countryCode in
2001 i18n.phonenumbers.PhoneNumberUtil.LEADING_ZERO_COUNTRIES_;
2006 * Convenience wrapper around isPossibleNumberWithReason. Instead of returning
2007 * the reason for failure, this method returns a boolean value.
2009 * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be
2011 * @return {boolean} true if the number is possible.
2013 i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumber =
2016 return this.isPossibleNumberWithReason(number) ==
2017 i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE;
2022 * Check whether a phone number is a possible number. It provides a more lenient
2023 * check than isValidNumber in the following sense:
2025 * 1. It only checks the length of phone numbers. In particular, it doesn't
2026 * check starting digits of the number.
2028 * 2. It doesn't attempt to figure out the type of the number, but uses general
2029 * rules which applies to all types of phone numbers in a country. Therefore, it
2030 * is much faster than isValidNumber.
2032 * 3. For fixed line numbers, many countries have the concept of area code,
2033 * which together with subscriber number constitute the national significant
2034 * number. It is sometimes okay to dial the subscriber number only when dialing
2035 * in the same area. This function will return true if the
2036 * subscriber-number-only version is passed in. On the other hand, because
2037 * isValidNumber validates using information on both starting digits (for fixed
2038 * line numbers, that would most likely be area codes) and length (obviously
2039 * includes the length of area codes for fixed line numbers), it will return
2040 * false for the subscriber-number-only version.
2042 * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be
2044 * @return {i18n.phonenumbers.PhoneNumberUtil.ValidationResult} a
2045 * ValidationResult object which indicates whether the number is possible.
2047 i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberWithReason =
2050 /** @type {number} */
2051 var countryCode = number.getCountryCodeOrDefault();
2052 // Note: For Russian Fed and NANPA numbers, we just use the rules from the
2053 // default region (US or Russia) since the getRegionCodeForNumber will not
2054 // work if the number is possible but not valid. This would need to be
2055 // revisited if the possible number pattern ever differed between various
2056 // countries within those plans.
2057 /** @type {string} */
2058 var regionCode = this.getRegionCodeForCountryCode(countryCode);
2059 if (!this.isValidRegionCode_(regionCode)) {
2060 return i18n.phonenumbers.PhoneNumberUtil.ValidationResult
2061 .INVALID_COUNTRY_CODE;
2063 /** @type {string} */
2064 var nationalNumber =
2065 i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
2066 /** @type {i18n.phonenumbers.PhoneNumberDesc} */
2067 var generalNumDesc = this.getMetadataForRegion(regionCode).getGeneralDesc();
2068 // Handling case of numbers with no metadata.
2069 if (!generalNumDesc.hasNationalNumberPattern()) {
2070 /** @type {number} */
2071 var numberLength = nationalNumber.length;
2072 if (numberLength < i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
2073 return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT;
2074 } else if (numberLength >
2075 i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_) {
2076 return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_LONG;
2078 return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE;
2081 /** @type {string} */
2082 var possibleNumberPattern =
2083 generalNumDesc.getPossibleNumberPatternOrDefault();
2084 /** @type {Array.<string> } */
2085 var matchedGroups = nationalNumber.match('^' + possibleNumberPattern);
2086 /** @type {string} */
2087 var firstGroup = matchedGroups ? matchedGroups[0] : '';
2088 if (firstGroup.length > 0) {
2089 return (firstGroup.length == nationalNumber.length) ?
2090 i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE :
2091 i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_LONG;
2093 return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT;
2099 * Check whether a phone number is a possible number given a number in the form
2100 * of a string, and the country where the number could be dialed from. It
2101 * provides a more lenient check than isValidNumber. See
2102 * isPossibleNumber(number) for details.
2104 * This method first parses the number, then invokes
2105 * isPossibleNumber(PhoneNumber number) with the resultant PhoneNumber object.
2107 * @param {string} number the number that needs to be checked, in the form of a
2109 * @param {string} countryDialingFrom the ISO 3166-1 two-letter country code
2110 * that denotes the country that we are expecting the number to be dialed
2111 * from. Note this is different from the country where the number belongs.
2112 * For example, the number +1 650 253 0000 is a number that belongs to US.
2113 * When written in this form, it could be dialed from any country. When it
2114 * is written as 00 1 650 253 0000, it could be dialed from any country
2115 * which uses an international dialling prefix of 00. When it is written as
2116 * 650 253 0000, it could only be dialed from within the US, and when
2117 * written as 253 0000, it could only be dialed from within a smaller area
2118 * in the US (Mountain View, CA, to be more specific).
2119 * @return {boolean} true if the number is possible.
2121 i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberString =
2122 function(number, countryDialingFrom) {
2125 return this.isPossibleNumber(this.parse(number, countryDialingFrom));
2133 * Attempts to extract a valid number from a phone number that is too long to be
2134 * valid, and resets the PhoneNumber object passed in to that valid version. If
2135 * no valid number could be extracted, the PhoneNumber object passed in will not
2137 * @param {i18n.phonenumbers.PhoneNumber} number a PhoneNumber object which
2138 * contains a number that is too long to be valid.
2139 * @return {boolean} true if a valid phone number can be successfully extracted.
2141 i18n.phonenumbers.PhoneNumberUtil.prototype.truncateTooLongNumber =
2144 if (this.isValidNumber(number)) {
2147 /** @type {i18n.phonenumbers.PhoneNumber} */
2148 var numberCopy = new i18n.phonenumbers.PhoneNumber();
2149 numberCopy.mergeFrom(number);
2150 /** @type {number} */
2151 var nationalNumber = number.getNationalNumberOrDefault();
2153 nationalNumber = Math.floor(nationalNumber / 10);
2154 numberCopy.setNationalNumber(nationalNumber);
2155 if (nationalNumber == 0 ||
2156 this.isPossibleNumberWithReason(numberCopy) ==
2157 i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT) {
2160 } while (!this.isValidNumber(numberCopy));
2161 number.setNationalNumber(nationalNumber);
2167 * Extracts country code from fullNumber, returns it and places the remaining
2168 * number in nationalNumber. It assumes that the leading plus sign or IDD has
2169 * already been removed. Returns 0 if fullNumber doesn't start with a valid
2170 * country code, and leaves nationalNumber unmodified.
2172 * @param {!goog.string.StringBuffer} fullNumber
2173 * @param {!goog.string.StringBuffer} nationalNumber
2176 i18n.phonenumbers.PhoneNumberUtil.prototype.extractCountryCode =
2177 function(fullNumber, nationalNumber) {
2179 /** @type {string} */
2180 var fullNumberStr = fullNumber.toString();
2181 /** @type {number} */
2182 var potentialCountryCode;
2183 /** @type {number} */
2184 var numberLength = fullNumberStr.length;
2186 i <= i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE_ &&
2187 i <= numberLength; ++i) {
2188 potentialCountryCode = parseInt(fullNumberStr.substring(0, i), 10);
2189 if (potentialCountryCode in
2190 i18n.phonenumbers.metadata.countryCodeToRegionCodeMap) {
2191 nationalNumber.append(fullNumberStr.substring(i));
2192 return potentialCountryCode;
2200 * Tries to extract a country code from a number. This method will return zero
2201 * if no country code is considered to be present. Country codes are extracted
2202 * in the following ways:
2203 * - by stripping the international dialing prefix of the country the person is
2204 * dialing from, if this is present in the number, and looking at the next
2206 * - by stripping the '+' sign if present and then looking at the next digits
2207 * - by comparing the start of the number and the country code of the default
2208 * region. If the number is not considered possible for the numbering plan of
2209 * the default region initially, but starts with the country code of this
2210 * region, validation will be reattempted after stripping this country code. If
2211 * this number is considered a possible number, then the first digits will be
2212 * considered the country code and removed as such.
2214 * It will throw a i18n.phonenumbers.Error if the number starts with a '+' but
2215 * the country code supplied after this does not match that of any known
2218 * @param {string} number non-normalized telephone number that we wish to
2219 * extract a country code from - may begin with '+'.
2220 * @param {i18n.phonenumbers.PhoneMetadata} defaultRegionMetadata metadata
2221 * about the region this number may be from.
2222 * @param {!goog.string.StringBuffer} nationalNumber a string buffer to store
2223 * the national significant number in, in the case that a country code was
2224 * extracted. The number is appended to any existing contents. If no country
2225 * code was extracted, this will be left unchanged.
2226 * @param {boolean} storeCountryCodeSource true if the country_code_source field
2227 * of phoneNumber should be populated.
2228 * @param {i18n.phonenumbers.PhoneNumber} phoneNumber the PhoneNumber object
2229 * that needs to be populated with country code and country code source.
2230 * Note the country code is always populated, whereas country code source is
2231 * only populated when keepCountryCodeSource is true.
2232 * @return {number} the country code extracted or 0 if none could be extracted.
2233 * @throws {i18n.phonenumbers.Error}
2235 i18n.phonenumbers.PhoneNumberUtil.prototype.maybeExtractCountryCode =
2236 function(number, defaultRegionMetadata, nationalNumber,
2237 storeCountryCodeSource, phoneNumber) {
2239 if (number.length == 0) {
2242 /** @type {!goog.string.StringBuffer} */
2243 var fullNumber = new goog.string.StringBuffer(number);
2244 // Set the default prefix to be something that will never match.
2245 /** @type {?string} */
2246 var possibleCountryIddPrefix;
2247 if (defaultRegionMetadata != null) {
2248 possibleCountryIddPrefix = defaultRegionMetadata.getInternationalPrefix();
2250 if (possibleCountryIddPrefix == null) {
2251 possibleCountryIddPrefix = 'NonMatch';
2254 /** @type {i18n.phonenumbers.PhoneNumber.CountryCodeSource} */
2255 var countryCodeSource = this.maybeStripInternationalPrefixAndNormalize(
2256 fullNumber, possibleCountryIddPrefix);
2257 if (storeCountryCodeSource) {
2258 phoneNumber.setCountryCodeSource(countryCodeSource);
2260 if (countryCodeSource !=
2261 i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY) {
2262 if (fullNumber.getLength() <
2263 i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
2264 throw i18n.phonenumbers.Error.TOO_SHORT_AFTER_IDD;
2266 /** @type {number} */
2267 var potentialCountryCode = this.extractCountryCode(fullNumber,
2269 if (potentialCountryCode != 0) {
2270 phoneNumber.setCountryCode(potentialCountryCode);
2271 return potentialCountryCode;
2274 // If this fails, they must be using a strange country code that we don't
2275 // recognize, or that doesn't exist.
2276 throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
2277 } else if (defaultRegionMetadata != null) {
2278 // Check to see if the number is valid for the default region already. If
2279 // not, we check to see if the country code for the default region is
2280 // present at the start of the number.
2281 /** @type {i18n.phonenumbers.PhoneNumberDesc} */
2282 var generalDesc = defaultRegionMetadata.getGeneralDesc();
2283 /** @type {RegExp} */
2284 var validNumberPattern = new RegExp(generalDesc.getNationalNumberPattern());
2285 if (!i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
2286 validNumberPattern, fullNumber.toString())) {
2287 /** @type {number} */
2288 var defaultCountryCode = defaultRegionMetadata.getCountryCodeOrDefault();
2289 /** @type {string} */
2290 var defaultCountryCodeString = '' + defaultCountryCode;
2291 /** @type {string} */
2292 var normalizedNumber = fullNumber.toString();
2293 if (goog.string.startsWith(normalizedNumber, defaultCountryCodeString)) {
2294 // If so, strip this, and see if the resultant number is valid.
2295 /** @type {!goog.string.StringBuffer} */
2296 var potentialNationalNumber = new goog.string.StringBuffer(
2297 normalizedNumber.substring(defaultCountryCodeString.length));
2298 this.maybeStripNationalPrefix(potentialNationalNumber,
2299 defaultRegionMetadata.getNationalPrefixForParsing(),
2300 defaultRegionMetadata.getNationalPrefixTransformRule(),
2301 validNumberPattern);
2302 /** @type {string} */
2303 var potentialNationalNumberStr = potentialNationalNumber.toString();
2304 /** @type {Array.<string> } */
2305 var matchedGroups = potentialNationalNumberStr.match(
2306 '^' + generalDesc.getPossibleNumberPattern());
2307 /** @type {number} */
2308 var possibleNumberMatchedLength = matchedGroups &&
2309 matchedGroups[0] != null && matchedGroups[0].length || 0;
2310 // If the resultant number is either valid, or still too long even with
2311 // the country code stripped, we consider this a better result and keep
2312 // the potential national number.
2313 if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
2314 validNumberPattern, potentialNationalNumberStr) ||
2315 possibleNumberMatchedLength > 0 &&
2316 possibleNumberMatchedLength != potentialNationalNumberStr.length) {
2317 nationalNumber.append(potentialNationalNumberStr);
2318 if (storeCountryCodeSource) {
2319 phoneNumber.setCountryCodeSource(
2320 i18n.phonenumbers.PhoneNumber.CountryCodeSource
2321 .FROM_NUMBER_WITHOUT_PLUS_SIGN);
2323 phoneNumber.setCountryCode(defaultCountryCode);
2324 return defaultCountryCode;
2329 // No country code present.
2330 phoneNumber.setCountryCode(0);
2336 * Strips the IDD from the start of the number if present. Helper function used
2337 * by maybeStripInternationalPrefixAndNormalize.
2339 * @param {RegExp} iddPattern the regular expression for the international
2341 * @param {!goog.string.StringBuffer} number the phone number that we wish to
2342 * strip any international dialing prefix from.
2343 * @return {boolean} true if an international prefix was present.
2346 i18n.phonenumbers.PhoneNumberUtil.prototype.parsePrefixAsIdd_ =
2347 function(iddPattern, number) {
2349 /** @type {string} */
2350 var numberStr = number.toString();
2351 if (numberStr.search(iddPattern) == 0) {
2352 /** @type {number} */
2353 var matchEnd = numberStr.match(iddPattern)[0].length;
2354 /** @type {Array.<string> } */
2355 var matchedGroups = numberStr.substring(matchEnd).match(
2356 i18n.phonenumbers.PhoneNumberUtil.CAPTURING_DIGIT_PATTERN_);
2357 if (matchedGroups && matchedGroups[1] != null &&
2358 matchedGroups[1].length > 0) {
2359 /** @type {string} */
2360 var normalizedGroup = i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(
2361 matchedGroups[1], i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS,
2363 if (normalizedGroup == '0') {
2368 number.append(numberStr.substring(matchEnd));
2376 * Strips any international prefix (such as +, 00, 011) present in the number
2377 * provided, normalizes the resulting number, and indicates if an international
2378 * prefix was present.
2380 * @param {!goog.string.StringBuffer} number the non-normalized telephone number
2381 * that we wish to strip any international dialing prefix from.
2382 * @param {string} possibleIddPrefix the international direct dialing prefix
2383 * from the country we think this number may be dialed in.
2384 * @return {i18n.phonenumbers.PhoneNumber.CountryCodeSource} the corresponding
2385 * CountryCodeSource if an international dialing prefix could be removed
2386 * from the number, otherwise CountryCodeSource.FROM_DEFAULT_COUNTRY if
2387 * the number did not seem to be in international format.
2389 i18n.phonenumbers.PhoneNumberUtil.prototype.
2390 maybeStripInternationalPrefixAndNormalize = function(number,
2391 possibleIddPrefix) {
2392 /** @type {string} */
2393 var numberStr = number.toString();
2394 if (numberStr.length == 0) {
2395 return i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY;
2397 // Check to see if the number begins with one or more plus signs.
2398 if (i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_PATTERN_.test(numberStr)) {
2399 numberStr = numberStr.replace(
2400 i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_PATTERN_, '');
2401 // Can now normalize the rest of the number since we've consumed the "+"
2402 // sign at the start.
2404 number.append(i18n.phonenumbers.PhoneNumberUtil.normalize(numberStr));
2405 return i18n.phonenumbers.PhoneNumber.CountryCodeSource
2406 .FROM_NUMBER_WITH_PLUS_SIGN;
2408 // Attempt to parse the first digits as an international prefix.
2409 /** @type {RegExp} */
2410 var iddPattern = new RegExp(possibleIddPrefix);
2411 if (this.parsePrefixAsIdd_(iddPattern, number)) {
2412 i18n.phonenumbers.PhoneNumberUtil.normalizeSB_(number);
2413 return i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD;
2415 // If still not found, then try and normalize the number and then try again.
2416 // This shouldn't be done before, since non-numeric characters (+ and ~) may
2417 // legally be in the international prefix.
2418 i18n.phonenumbers.PhoneNumberUtil.normalizeSB_(number);
2419 return this.parsePrefixAsIdd_(iddPattern, number) ?
2420 i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD :
2421 i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY;
2426 * Strips any national prefix (such as 0, 1) present in the number provided.
2428 * @param {!goog.string.StringBuffer} number the normalized telephone number
2429 * that we wish to strip any national dialing prefix from.
2430 * @param {?string} possibleNationalPrefix a regex that represents the national
2431 * direct dialing prefix from the country we think this number may be dialed
2433 * @param {?string} transformRule the string that specifies how number should be
2434 * transformed according to the regex specified in possibleNationalPrefix.
2435 * @param {RegExp} nationalNumberRule a regular expression that specifies what a
2436 * valid phonenumber from this region should look like after any national
2437 * prefix was stripped or transformed.
2439 i18n.phonenumbers.PhoneNumberUtil.prototype.maybeStripNationalPrefix =
2440 function(number, possibleNationalPrefix, transformRule,
2441 nationalNumberRule) {
2443 /** @type {string} */
2444 var numberStr = number.toString();
2445 /** @type {number} */
2446 var numberLength = numberStr.length;
2447 if (numberLength == 0 || possibleNationalPrefix == null ||
2448 possibleNationalPrefix.length == 0) {
2449 // Early return for numbers of zero length.
2452 // Attempt to parse the first digits as a national prefix.
2453 /** @type {RegExp} */
2454 var re = new RegExp('^' + possibleNationalPrefix);
2455 /** @type {Array.<string>} */
2456 var m = re.exec(numberStr);
2458 /** @type {string} */
2459 var transformedNumber;
2460 // m[1] == null implies nothing was captured by the capturing groups in
2461 // possibleNationalPrefix; therefore, no transformation is necessary, and
2462 // we just remove the national prefix.
2463 if (transformRule == null || transformRule.length == 0 || m[1] == null ||
2465 transformedNumber = numberStr.substring(m[0].length);
2467 transformedNumber = numberStr.replace(re, transformRule);
2469 // Check that the resultant number is viable. If not, return.
2470 if (!i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(nationalNumberRule,
2471 transformedNumber)) {
2475 number.append(transformedNumber);
2481 * Strips any extension (as in, the part of the number dialled after the call is
2482 * connected, usually indicated with extn, ext, x or similar) from the end of
2483 * the number, and returns it.
2485 * @param {!goog.string.StringBuffer} number the non-normalized telephone number
2486 * that we wish to strip the extension from.
2487 * @return {string} the phone extension.
2489 i18n.phonenumbers.PhoneNumberUtil.prototype.maybeStripExtension =
2492 /** @type {string} */
2493 var numberStr = number.toString();
2494 /** @type {number} */
2496 numberStr.search(i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_);
2497 // If we find a potential extension, and the number preceding this is a viable
2498 // number, we assume it is an extension.
2499 if (mStart >= 0 && i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber(
2500 numberStr.substring(0, mStart))) {
2501 // The numbers are captured into groups in the regular expression.
2502 /** @type {Array.<string>} */
2504 numberStr.match(i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_);
2505 /** @type {number} */
2506 var matchedGroupsLength = matchedGroups.length;
2507 for (var i = 1; i < matchedGroupsLength; ++i) {
2508 if (matchedGroups[i] != null && matchedGroups[i].length > 0) {
2510 number.append(numberStr.substring(0, mStart));
2511 return matchedGroups[i];
2520 * Checks to see that the region code used is valid, or if it is not valid, that
2521 * the number to parse starts with a + symbol so that we can attempt to infer
2522 * the country from the number.
2523 * @param {string} numberToParse number that we are attempting to parse.
2524 * @param {?string} defaultCountry the ISO 3166-1 two-letter country code that
2525 * denotes the country that we are expecting the number to be from.
2526 * @return {boolean} false if it cannot use the region provided and the region
2527 * cannot be inferred.
2530 i18n.phonenumbers.PhoneNumberUtil.prototype.checkRegionForParsing_ = function(
2531 numberToParse, defaultCountry) {
2532 // If the number is null or empty, we can't guess the country code.
2533 return this.isValidRegionCode_(defaultCountry) ||
2534 (numberToParse != null && numberToParse.length > 0 &&
2535 i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_PATTERN_.test(
2541 * Parses a string and returns it in proto buffer format. This method will throw
2542 * a i18n.phonenumbers.Error if the number is not considered to be a possible
2543 * number. Note that validation of whether the number is actually a valid number
2544 * for a particular country/region is not performed. This can be done separately
2545 * with isValidNumber.
2547 * @param {string} numberToParse number that we are attempting to parse. This
2548 * can contain formatting such as +, ( and -, as well as a phone number
2550 * @param {?string} defaultCountry the ISO 3166-1 two-letter country code that
2551 * denotes the country that we are expecting the number to be from. This is
2552 * only used if the number being parsed is not written in international
2553 * format. The country code for the number in this case would be stored as
2554 * that of the default country supplied. If the number is guaranteed to
2555 * start with a '+' followed by the country code, then 'ZZ' or null can be
2557 * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
2558 * with the parsed number.
2559 * @throws {i18n.phonenumbers.Error} if the string is not considered to be a
2560 * viable phone number or if no default country was supplied and the number
2561 * is not in international format (does not start with +).
2563 i18n.phonenumbers.PhoneNumberUtil.prototype.parse = function(numberToParse,
2565 return this.parseHelper_(numberToParse, defaultCountry, false, true);
2570 * Parses a string and returns it in proto buffer format. This method differs
2571 * from parse() in that it always populates the raw_input field of the protocol
2572 * buffer with numberToParse as well as the country_code_source field.
2574 * @param {string} numberToParse number that we are attempting to parse. This
2575 * can contain formatting such as +, ( and -, as well as a phone number
2577 * @param {?string} defaultCountry the ISO 3166-1 two-letter country code that
2578 * denotes the country that we are expecting the number to be from. This is
2579 * only used if the number being parsed is not written in international
2580 * format. The country code for the number in this case would be stored as
2581 * that of the default country supplied.
2582 * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
2583 * with the parsed number.
2584 * @throws {i18n.phonenumbers.Error} if the string is not considered to be a
2585 * viable phone number or if no default country was supplied and the number
2586 * is not in international format (does not start with +).
2588 i18n.phonenumbers.PhoneNumberUtil.prototype.parseAndKeepRawInput =
2589 function(numberToParse, defaultCountry) {
2591 if (!this.isValidRegionCode_(defaultCountry)) {
2592 if (numberToParse.length > 0 && numberToParse.charAt(0) !=
2593 i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
2594 throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
2597 return this.parseHelper_(numberToParse, defaultCountry, true, true);
2602 * Parses a string and returns it in proto buffer format. This method is the
2603 * same as the public parse() method, with the exception that it allows the
2604 * default country to be null, for use by isNumberMatch().
2606 * @param {string} numberToParse number that we are attempting to parse. This
2607 * can contain formatting such as +, ( and -, as well as a phone number
2609 * @param {?string} defaultCountry the ISO 3166-1 two-letter country code that
2610 * denotes the country that we are expecting the number to be from. This is
2611 * only used if the number being parsed is not written in international
2612 * format. The country code for the number in this case would be stored as
2613 * that of the default country supplied.
2614 * @param {boolean} keepRawInput whether to populate the raw_input field of the
2615 * phoneNumber with numberToParse.
2616 * @param {boolean} checkRegion should be set to false if it is permitted for
2617 * the default country to be null or unknown ('ZZ').
2618 * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
2619 * with the parsed number.
2620 * @throws {i18n.phonenumbers.Error}
2623 i18n.phonenumbers.PhoneNumberUtil.prototype.parseHelper_ =
2624 function(numberToParse, defaultCountry, keepRawInput, checkRegion) {
2626 if (numberToParse == null) {
2627 throw i18n.phonenumbers.Error.NOT_A_NUMBER;
2629 // Extract a possible number from the string passed in (this strips leading
2630 // characters that could not be the start of a phone number.)
2631 /** @type {string} */
2633 i18n.phonenumbers.PhoneNumberUtil.extractPossibleNumber(numberToParse);
2634 if (!i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber(number)) {
2635 throw i18n.phonenumbers.Error.NOT_A_NUMBER;
2638 // Check the country supplied is valid, or that the extracted number starts
2639 // with some sort of + sign so the number's region can be determined.
2640 if (checkRegion && !this.checkRegionForParsing_(number, defaultCountry)) {
2641 throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
2644 /** @type {i18n.phonenumbers.PhoneNumber} */
2645 var phoneNumber = new i18n.phonenumbers.PhoneNumber();
2647 phoneNumber.setRawInput(numberToParse);
2649 /** @type {!goog.string.StringBuffer} */
2650 var nationalNumber = new goog.string.StringBuffer(number);
2651 // Attempt to parse extension first, since it doesn't require
2652 // country-specific data and we want to have the non-normalised number here.
2653 /** @type {string} */
2654 var extension = this.maybeStripExtension(nationalNumber);
2655 if (extension.length > 0) {
2656 phoneNumber.setExtension(extension);
2659 /** @type {i18n.phonenumbers.PhoneMetadata} */
2660 var countryMetadata = this.getMetadataForRegion(defaultCountry);
2661 // Check to see if the number is given in international format so we know
2662 // whether this number is from the default country or not.
2663 /** @type {!goog.string.StringBuffer} */
2664 var normalizedNationalNumber = new goog.string.StringBuffer();
2665 /** @type {number} */
2666 var countryCode = this.maybeExtractCountryCode(nationalNumber.toString(),
2667 countryMetadata, normalizedNationalNumber, keepRawInput, phoneNumber);
2668 if (countryCode != 0) {
2669 /** @type {string} */
2670 var phoneNumberRegion = this.getRegionCodeForCountryCode(countryCode);
2671 if (phoneNumberRegion != defaultCountry) {
2672 countryMetadata = this.getMetadataForRegion(phoneNumberRegion);
2675 // If no extracted country code, use the region supplied instead. The
2676 // national number is just the normalized version of the number we were
2678 i18n.phonenumbers.PhoneNumberUtil.normalizeSB_(nationalNumber);
2679 normalizedNationalNumber.append(nationalNumber.toString());
2680 if (defaultCountry != null) {
2681 countryCode = countryMetadata.getCountryCodeOrDefault();
2682 phoneNumber.setCountryCode(countryCode);
2683 } else if (keepRawInput) {
2684 phoneNumber.clearCountryCodeSource();
2687 if (normalizedNationalNumber.getLength() <
2688 i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
2689 throw i18n.phonenumbers.Error.TOO_SHORT_NSN;
2692 if (countryMetadata != null) {
2693 /** @type {RegExp} */
2694 var validNumberPattern =
2695 new RegExp(countryMetadata.getGeneralDesc().getNationalNumberPattern());
2696 this.maybeStripNationalPrefix(normalizedNationalNumber, countryMetadata
2697 .getNationalPrefixForParsing(), countryMetadata
2698 .getNationalPrefixTransformRule(), validNumberPattern);
2700 /** @type {string} */
2701 var normalizedNationalNumberStr = normalizedNationalNumber.toString();
2702 /** @type {number} */
2703 var lengthOfNationalNumber = normalizedNationalNumberStr.length;
2704 if (lengthOfNationalNumber <
2705 i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
2706 throw i18n.phonenumbers.Error.TOO_SHORT_NSN;
2708 if (lengthOfNationalNumber >
2709 i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_) {
2710 throw i18n.phonenumbers.Error.TOO_LONG;
2712 if (normalizedNationalNumberStr.charAt(0) == '0' &&
2713 i18n.phonenumbers.PhoneNumberUtil.isLeadingZeroCountry(countryCode)) {
2714 phoneNumber.setItalianLeadingZero(true);
2716 phoneNumber.setNationalNumber(parseInt(normalizedNationalNumberStr, 10));
2722 * Takes two phone numbers and compares them for equality.
2724 * Returns EXACT_MATCH if the country code, NSN, presence of a leading zero for
2725 * Italian numbers and any extension present are the same. Returns NSN_MATCH if
2726 * either or both has no country specified, and the NSNs and extensions are the
2727 * same. Returns SHORT_NSN_MATCH if either or both has no country specified, or
2728 * the country specified is the same, and one NSN could be a shorter version of
2729 * the other number. This includes the case where one has an extension
2730 * specified, and the other does not. Returns NO_MATCH otherwise. For example,
2731 * the numbers +1 345 657 1234 and 657 1234 are a SHORT_NSN_MATCH. The numbers
2732 * +1 345 657 1234 and 345 657 are a NO_MATCH.
2734 * @param {i18n.phonenumbers.PhoneNumber|string} firstNumberIn first number to
2735 * compare. If it is a string it can contain formatting, and can have
2736 * country code specified with + at the start.
2737 * @param {i18n.phonenumbers.PhoneNumber|string} secondNumberIn second number to
2738 * compare. If it is a string it can contain formatting, and can have
2739 * country code specified with + at the start.
2740 * @return {i18n.phonenumbers.PhoneNumberUtil.MatchType} NOT_A_NUMBER, NO_MATCH,
2741 * SHORT_NSN_MATCH, NSN_MATCH or EXACT_MATCH depending on the level of
2742 * equality of the two numbers, described in the method definition.
2744 i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberMatch =
2745 function(firstNumberIn, secondNumberIn) {
2747 // If the input arguements are strings parse them to a proto buffer format.
2748 // Else make copies of the phone numbers so that the numbers passed in are not
2750 /** @type {i18n.phonenumbers.PhoneNumber} */
2752 /** @type {i18n.phonenumbers.PhoneNumber} */
2754 if (typeof firstNumberIn == 'string') {
2755 // First see if the first number has an implicit country code, by attempting
2758 firstNumber = this.parse(
2759 firstNumberIn, i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_);
2761 if (e != i18n.phonenumbers.Error.INVALID_COUNTRY_CODE) {
2762 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
2764 // The first number has no country code. EXACT_MATCH is no longer
2765 // possible. We parse it as if the region was the same as that for the
2766 // second number, and if EXACT_MATCH is returned, we replace this with
2768 if (typeof secondNumberIn != 'string') {
2769 /** @type {string} */
2770 var secondNumberRegion = this.getRegionCodeForCountryCode(
2771 secondNumberIn.getCountryCodeOrDefault());
2772 if (secondNumberRegion !=
2773 i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_) {
2775 firstNumber = this.parse(firstNumberIn, secondNumberRegion);
2777 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
2779 /** @type {i18n.phonenumbers.PhoneNumberUtil.MatchType} */
2780 var match = this.isNumberMatch(firstNumber, secondNumberIn);
2782 i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH) {
2783 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NSN_MATCH;
2788 // If the second number is a string or doesn't have a valid country code,
2789 // we parse the first number without country code.
2791 firstNumber = this.parseHelper_(firstNumberIn, null, false, false);
2793 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
2797 firstNumber = new i18n.phonenumbers.PhoneNumber();
2798 firstNumber.mergeFrom(firstNumberIn);
2800 if (typeof secondNumberIn == 'string') {
2802 secondNumber = this.parse(
2803 secondNumberIn, i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_);
2804 return this.isNumberMatch(firstNumberIn, secondNumber);
2806 if (e != i18n.phonenumbers.Error.INVALID_COUNTRY_CODE) {
2807 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
2809 return this.isNumberMatch(secondNumberIn, firstNumber);
2812 secondNumber = new i18n.phonenumbers.PhoneNumber();
2813 secondNumber.mergeFrom(secondNumberIn);
2815 // First clear raw_input and country_code_source field and any empty-string
2816 // extensions so that
2817 // we can use the PhoneNumber.exactlySameAs() method.
2818 firstNumber.clearRawInput();
2819 firstNumber.clearCountryCodeSource();
2820 secondNumber.clearRawInput();
2821 secondNumber.clearCountryCodeSource();
2822 if (firstNumber.hasExtension() && firstNumber.getExtension().length == 0) {
2823 firstNumber.clearExtension();
2825 if (secondNumber.hasExtension() && secondNumber.getExtension().length == 0) {
2826 secondNumber.clearExtension();
2829 // Early exit if both had extensions and these are different.
2830 if (firstNumber.hasExtension() && secondNumber.hasExtension() &&
2831 firstNumber.getExtension() != secondNumber.getExtension()) {
2832 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH;
2834 /** @type {number} */
2835 var firstNumberCountryCode = firstNumber.getCountryCodeOrDefault();
2836 /** @type {number} */
2837 var secondNumberCountryCode = secondNumber.getCountryCodeOrDefault();
2838 // Both had country code specified.
2839 if (firstNumberCountryCode != 0 && secondNumberCountryCode != 0) {
2840 if (firstNumber.exactlySameAs(secondNumber)) {
2841 return i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH;
2842 } else if (firstNumberCountryCode == secondNumberCountryCode &&
2843 this.isNationalNumberSuffixOfTheOther_(firstNumber, secondNumber)) {
2844 // A SHORT_NSN_MATCH occurs if there is a difference because of the
2845 // presence or absence of an 'Italian leading zero', the presence or
2846 // absence of an extension, or one NSN being a shorter variant of the
2848 return i18n.phonenumbers.PhoneNumberUtil.MatchType.SHORT_NSN_MATCH;
2850 // This is not a match.
2851 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH;
2853 // Checks cases where one or both country codes were not specified. To make
2854 // equality checks easier, we first set the country codes to be equal.
2855 firstNumber.setCountryCode(0);
2856 secondNumber.setCountryCode(0);
2857 // If all else was the same, then this is an NSN_MATCH.
2858 if (firstNumber.exactlySameAs(secondNumber)) {
2859 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NSN_MATCH;
2861 if (this.isNationalNumberSuffixOfTheOther_(firstNumber, secondNumber)) {
2862 return i18n.phonenumbers.PhoneNumberUtil.MatchType.SHORT_NSN_MATCH;
2864 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH;
2869 * Returns true when one national number is the suffix of the other or both are
2872 * @param {i18n.phonenumbers.PhoneNumber} firstNumber the first PhoneNumber
2874 * @param {i18n.phonenumbers.PhoneNumber} secondNumber the second PhoneNumber
2876 * @return {boolean} true if one PhoneNumber is the suffix of the other one.
2879 i18n.phonenumbers.PhoneNumberUtil.prototype.isNationalNumberSuffixOfTheOther_ =
2880 function(firstNumber, secondNumber) {
2882 /** @type {string} */
2883 var firstNumberNationalNumber = '' + firstNumber.getNationalNumber();
2884 /** @type {string} */
2885 var secondNumberNationalNumber = '' + secondNumber.getNationalNumber();
2886 // Note that endsWith returns true if the numbers are equal.
2887 return goog.string.endsWith(firstNumberNationalNumber,
2888 secondNumberNationalNumber) ||
2889 goog.string.endsWith(secondNumberNationalNumber,
2890 firstNumberNationalNumber);
2895 * Returns true if the number can only be dialled from within the country. If
2896 * unknown, or the number can be dialled from outside the country as well,
2897 * returns false. Does not check the number is a valid number.
2898 * TODO: Make this method public when we have enough metadata to make it
2899 * worthwhile. Currently visible for testing purposes only.
2901 * @param {i18n.phonenumbers.PhoneNumber} number the phone-number for which we
2902 * want to know whether it is only diallable from within the country.
2903 * @return {boolean} true if the number can only be dialled from within the
2906 i18n.phonenumbers.PhoneNumberUtil.prototype.canBeInternationallyDialled =
2908 /** @type {?string} */
2909 var regionCode = this.getRegionCodeForNumber(number);
2910 /** @type {string} */
2911 var nationalSignificantNumber =
2912 i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
2913 if (!this.isValidRegionCode_(regionCode)) {
2916 /** @type {i18n.phonenumbers.PhoneMetadata} */
2917 var metadata = this.getMetadataForRegion(regionCode);
2918 return !this.isNumberMatchingDesc_(nationalSignificantNumber,
2919 metadata.getNoInternationalDialling());
2924 * Check whether the entire input sequence can be matched against the regular
2927 * @param {RegExp|string} regex the regular expression to match against.
2928 * @param {string} str the string to test.
2929 * @return {boolean} true if str can be matched entirely against regex.
2932 i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_ = function(regex, str) {
2933 /** @type {Array.<string>} */
2934 var matchedGroups = str.match(regex);
2935 if (matchedGroups && matchedGroups[0].length == str.length) {
2943 * @param {i18n.phonenumbers.PhoneNumber} other
2946 i18n.phonenumbers.PhoneNumber.prototype.exactlySameAs = function(other) {
2947 return other != null &&
2948 this.getCountryCode() == other.getCountryCode() &&
2949 this.getNationalNumber() == other.getNationalNumber() &&
2950 this.getExtension() == other.getExtension() &&
2951 this.getItalianLeadingZero() == other.getItalianLeadingZero() &&
2952 this.getRawInput() == other.getRawInput() &&
2953 this.getCountryCodeSource() == other.getCountryCodeSource();
2958 * @param {i18n.phonenumbers.PhoneNumberDesc} other
2961 i18n.phonenumbers.PhoneNumberDesc.prototype.exactlySameAs = function(other) {
2962 return other != null &&
2963 this.getNationalNumberPattern() == other.getNationalNumberPattern() &&
2964 this.getPossibleNumberPattern() == other.getPossibleNumberPattern() &&
2965 this.getExampleNumber() == other.getExampleNumber();
2970 * @param {i18n.phonenumbers.PhoneNumber} other
2971 * @return {i18n.phonenumbers.PhoneNumber}
2972 * @suppress {accessControls}
2974 i18n.phonenumbers.PhoneNumber.prototype.mergeFrom = function(other) {
2976 this.values_ = goog.cloneObject(other.values_);
2983 * @param {i18n.phonenumbers.NumberFormat} other
2984 * @return {i18n.phonenumbers.NumberFormat}
2985 * @suppress {accessControls}
2987 i18n.phonenumbers.NumberFormat.prototype.mergeFrom = function(other) {
2989 this.values_ = goog.cloneObject(other.values_);