1/** 2 * @license 3 * Copyright (C) 2010 The Libphonenumber Authors. 4 * 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 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 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. 16 */ 17 18/** 19 * @fileoverview Utility for international phone numbers. 20 * Functionality includes formatting, parsing and validation. 21 * (based on the java implementation). 22 * 23 * NOTE: A lot of methods in this class require Region Code strings. These must 24 * be provided using CLDR two-letter region-code format. These should be in 25 * upper-case. The list of the codes can be found here: 26 * http://www.unicode.org/cldr/charts/30/supplemental/territory_information.html 27 */ 28 29goog.provide('i18n.phonenumbers.Error'); 30goog.provide('i18n.phonenumbers.PhoneNumberFormat'); 31goog.provide('i18n.phonenumbers.PhoneNumberType'); 32goog.provide('i18n.phonenumbers.PhoneNumberUtil'); 33goog.provide('i18n.phonenumbers.PhoneNumberUtil.MatchType'); 34goog.provide('i18n.phonenumbers.PhoneNumberUtil.ValidationResult'); 35 36goog.require('goog.object'); 37goog.require('goog.proto2.PbLiteSerializer'); 38goog.require('goog.string'); 39goog.require('goog.string.StringBuffer'); 40goog.require('i18n.phonenumbers.NumberFormat'); 41goog.require('i18n.phonenumbers.PhoneMetadata'); 42goog.require('i18n.phonenumbers.PhoneNumber'); 43goog.require('i18n.phonenumbers.PhoneNumber.CountryCodeSource'); 44goog.require('i18n.phonenumbers.PhoneNumberDesc'); 45goog.require('i18n.phonenumbers.metadata'); 46 47 48 49/** 50 * @constructor 51 * @private 52 */ 53i18n.phonenumbers.PhoneNumberUtil = function() { 54 /** 55 * A mapping from a region code to the PhoneMetadata for that region. 56 * @type {Object.<string, i18n.phonenumbers.PhoneMetadata>} 57 */ 58 this.regionToMetadataMap = {}; 59}; 60goog.addSingletonGetter(i18n.phonenumbers.PhoneNumberUtil); 61 62 63/** 64 * Errors encountered when parsing phone numbers. 65 * 66 * @enum {string} 67 */ 68i18n.phonenumbers.Error = { 69 INVALID_COUNTRY_CODE: 'Invalid country calling code', 70 // This generally indicates the string passed in had less than 3 digits in it. 71 // More specifically, the number failed to match the regular expression 72 // VALID_PHONE_NUMBER. 73 NOT_A_NUMBER: 'The string supplied did not seem to be a phone number', 74 // This indicates the string started with an international dialing prefix, but 75 // after this was stripped from the number, had less digits than any valid 76 // phone number (including country calling code) could have. 77 TOO_SHORT_AFTER_IDD: 'Phone number too short after IDD', 78 // This indicates the string, after any country calling code has been 79 // stripped, had less digits than any valid phone number could have. 80 TOO_SHORT_NSN: 'The string supplied is too short to be a phone number', 81 // This indicates the string had more digits than any valid phone number could 82 // have. 83 TOO_LONG: 'The string supplied is too long to be a phone number' 84}; 85 86 87/** 88 * @const 89 * @type {number} 90 * @private 91 */ 92i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_ = 1; 93 94 95/** 96 * The minimum length of the national significant number. 97 * 98 * @const 99 * @type {number} 100 * @private 101 */ 102i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_ = 2; 103 104 105/** 106 * The ITU says the maximum length should be 15, but we have found longer 107 * numbers in Germany. 108 * 109 * @const 110 * @type {number} 111 * @private 112 */ 113i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_ = 17; 114 115 116/** 117 * The maximum length of the country calling code. 118 * 119 * @const 120 * @type {number} 121 * @private 122 */ 123i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE_ = 3; 124 125 126/** 127 * We don't allow input strings for parsing to be longer than 250 chars. This 128 * prevents malicious input from consuming CPU. 129 * 130 * @const 131 * @type {number} 132 * @private 133 */ 134i18n.phonenumbers.PhoneNumberUtil.MAX_INPUT_STRING_LENGTH_ = 250; 135 136 137/** 138 * Region-code for the unknown region. 139 * 140 * @const 141 * @type {string} 142 * @private 143 */ 144i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_ = 'ZZ'; 145 146 147/** 148 * The prefix that needs to be inserted in front of a Colombian landline number 149 * when dialed from a mobile phone in Colombia. 150 * 151 * @const 152 * @type {string} 153 * @private 154 */ 155i18n.phonenumbers.PhoneNumberUtil.COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX_ = '3'; 156 157 158/** 159 * Map of country calling codes that use a mobile token before the area code. 160 * One example of when this is relevant is when determining the length of the 161 * national destination code, which should be the length of the area code plus 162 * the length of the mobile token. 163 * 164 * @const 165 * @type {!Object.<number, string>} 166 * @private 167 */ 168i18n.phonenumbers.PhoneNumberUtil.MOBILE_TOKEN_MAPPINGS_ = { 169 54: '9' 170}; 171 172 173/** 174 * Set of country calling codes that have geographically assigned mobile 175 * numbers. This may not be complete; we add calling codes case by case, as we 176 * find geographical mobile numbers or hear from user reports. 177 * 178 * @const 179 * @type {!Array.<number>} 180 * @private 181 */ 182i18n.phonenumbers.PhoneNumberUtil.GEO_MOBILE_COUNTRIES_ = [ 183 52, // Mexico 184 54, // Argentina 185 55 // Brazil 186]; 187 188 189/** 190 * The PLUS_SIGN signifies the international prefix. 191 * 192 * @const 193 * @type {string} 194 */ 195i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN = '+'; 196 197 198/** 199 * @const 200 * @type {string} 201 * @private 202 */ 203i18n.phonenumbers.PhoneNumberUtil.STAR_SIGN_ = '*'; 204 205 206/** 207 * The RFC 3966 format for extensions. 208 * 209 * @const 210 * @type {string} 211 * @private 212 */ 213i18n.phonenumbers.PhoneNumberUtil.RFC3966_EXTN_PREFIX_ = ';ext='; 214 215 216/** 217 * @const 218 * @type {string} 219 * @private 220 */ 221i18n.phonenumbers.PhoneNumberUtil.RFC3966_PREFIX_ = 'tel:'; 222 223 224/** 225 * @const 226 * @type {string} 227 * @private 228 */ 229i18n.phonenumbers.PhoneNumberUtil.RFC3966_PHONE_CONTEXT_ = ';phone-context='; 230 231 232/** 233 * @const 234 * @type {string} 235 * @private 236 */ 237i18n.phonenumbers.PhoneNumberUtil.RFC3966_ISDN_SUBADDRESS_ = ';isub='; 238 239 240/** 241 * These mappings map a character (key) to a specific digit that should replace 242 * it for normalization purposes. Non-European digits that may be used in phone 243 * numbers are mapped to a European equivalent. 244 * 245 * @const 246 * @type {!Object.<string, string>} 247 */ 248i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS = { 249 '0': '0', 250 '1': '1', 251 '2': '2', 252 '3': '3', 253 '4': '4', 254 '5': '5', 255 '6': '6', 256 '7': '7', 257 '8': '8', 258 '9': '9', 259 '\uFF10': '0', // Fullwidth digit 0 260 '\uFF11': '1', // Fullwidth digit 1 261 '\uFF12': '2', // Fullwidth digit 2 262 '\uFF13': '3', // Fullwidth digit 3 263 '\uFF14': '4', // Fullwidth digit 4 264 '\uFF15': '5', // Fullwidth digit 5 265 '\uFF16': '6', // Fullwidth digit 6 266 '\uFF17': '7', // Fullwidth digit 7 267 '\uFF18': '8', // Fullwidth digit 8 268 '\uFF19': '9', // Fullwidth digit 9 269 '\u0660': '0', // Arabic-indic digit 0 270 '\u0661': '1', // Arabic-indic digit 1 271 '\u0662': '2', // Arabic-indic digit 2 272 '\u0663': '3', // Arabic-indic digit 3 273 '\u0664': '4', // Arabic-indic digit 4 274 '\u0665': '5', // Arabic-indic digit 5 275 '\u0666': '6', // Arabic-indic digit 6 276 '\u0667': '7', // Arabic-indic digit 7 277 '\u0668': '8', // Arabic-indic digit 8 278 '\u0669': '9', // Arabic-indic digit 9 279 '\u06F0': '0', // Eastern-Arabic digit 0 280 '\u06F1': '1', // Eastern-Arabic digit 1 281 '\u06F2': '2', // Eastern-Arabic digit 2 282 '\u06F3': '3', // Eastern-Arabic digit 3 283 '\u06F4': '4', // Eastern-Arabic digit 4 284 '\u06F5': '5', // Eastern-Arabic digit 5 285 '\u06F6': '6', // Eastern-Arabic digit 6 286 '\u06F7': '7', // Eastern-Arabic digit 7 287 '\u06F8': '8', // Eastern-Arabic digit 8 288 '\u06F9': '9' // Eastern-Arabic digit 9 289}; 290 291 292/** 293 * A map that contains characters that are essential when dialling. That means 294 * any of the characters in this map must not be removed from a number when 295 * dialling, otherwise the call will not reach the intended destination. 296 * 297 * @const 298 * @type {!Object.<string, string>} 299 * @private 300 */ 301i18n.phonenumbers.PhoneNumberUtil.DIALLABLE_CHAR_MAPPINGS_ = { 302 '0': '0', 303 '1': '1', 304 '2': '2', 305 '3': '3', 306 '4': '4', 307 '5': '5', 308 '6': '6', 309 '7': '7', 310 '8': '8', 311 '9': '9', 312 '+': i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN, 313 '*': '*', 314 '#': '#' 315}; 316 317 318/** 319 * Only upper-case variants of alpha characters are stored. 320 * 321 * @const 322 * @type {!Object.<string, string>} 323 * @private 324 */ 325i18n.phonenumbers.PhoneNumberUtil.ALPHA_MAPPINGS_ = { 326 'A': '2', 327 'B': '2', 328 'C': '2', 329 'D': '3', 330 'E': '3', 331 'F': '3', 332 'G': '4', 333 'H': '4', 334 'I': '4', 335 'J': '5', 336 'K': '5', 337 'L': '5', 338 'M': '6', 339 'N': '6', 340 'O': '6', 341 'P': '7', 342 'Q': '7', 343 'R': '7', 344 'S': '7', 345 'T': '8', 346 'U': '8', 347 'V': '8', 348 'W': '9', 349 'X': '9', 350 'Y': '9', 351 'Z': '9' 352}; 353 354 355/** 356 * For performance reasons, amalgamate both into one map. 357 * 358 * @const 359 * @type {!Object.<string, string>} 360 * @private 361 */ 362i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_ = { 363 '0': '0', 364 '1': '1', 365 '2': '2', 366 '3': '3', 367 '4': '4', 368 '5': '5', 369 '6': '6', 370 '7': '7', 371 '8': '8', 372 '9': '9', 373 '\uFF10': '0', // Fullwidth digit 0 374 '\uFF11': '1', // Fullwidth digit 1 375 '\uFF12': '2', // Fullwidth digit 2 376 '\uFF13': '3', // Fullwidth digit 3 377 '\uFF14': '4', // Fullwidth digit 4 378 '\uFF15': '5', // Fullwidth digit 5 379 '\uFF16': '6', // Fullwidth digit 6 380 '\uFF17': '7', // Fullwidth digit 7 381 '\uFF18': '8', // Fullwidth digit 8 382 '\uFF19': '9', // Fullwidth digit 9 383 '\u0660': '0', // Arabic-indic digit 0 384 '\u0661': '1', // Arabic-indic digit 1 385 '\u0662': '2', // Arabic-indic digit 2 386 '\u0663': '3', // Arabic-indic digit 3 387 '\u0664': '4', // Arabic-indic digit 4 388 '\u0665': '5', // Arabic-indic digit 5 389 '\u0666': '6', // Arabic-indic digit 6 390 '\u0667': '7', // Arabic-indic digit 7 391 '\u0668': '8', // Arabic-indic digit 8 392 '\u0669': '9', // Arabic-indic digit 9 393 '\u06F0': '0', // Eastern-Arabic digit 0 394 '\u06F1': '1', // Eastern-Arabic digit 1 395 '\u06F2': '2', // Eastern-Arabic digit 2 396 '\u06F3': '3', // Eastern-Arabic digit 3 397 '\u06F4': '4', // Eastern-Arabic digit 4 398 '\u06F5': '5', // Eastern-Arabic digit 5 399 '\u06F6': '6', // Eastern-Arabic digit 6 400 '\u06F7': '7', // Eastern-Arabic digit 7 401 '\u06F8': '8', // Eastern-Arabic digit 8 402 '\u06F9': '9', // Eastern-Arabic digit 9 403 'A': '2', 404 'B': '2', 405 'C': '2', 406 'D': '3', 407 'E': '3', 408 'F': '3', 409 'G': '4', 410 'H': '4', 411 'I': '4', 412 'J': '5', 413 'K': '5', 414 'L': '5', 415 'M': '6', 416 'N': '6', 417 'O': '6', 418 'P': '7', 419 'Q': '7', 420 'R': '7', 421 'S': '7', 422 'T': '8', 423 'U': '8', 424 'V': '8', 425 'W': '9', 426 'X': '9', 427 'Y': '9', 428 'Z': '9' 429}; 430 431 432/** 433 * Separate map of all symbols that we wish to retain when formatting alpha 434 * numbers. This includes digits, ASCII letters and number grouping symbols such 435 * as '-' and ' '. 436 * 437 * @const 438 * @type {!Object.<string, string>} 439 * @private 440 */ 441i18n.phonenumbers.PhoneNumberUtil.ALL_PLUS_NUMBER_GROUPING_SYMBOLS_ = { 442 '0': '0', 443 '1': '1', 444 '2': '2', 445 '3': '3', 446 '4': '4', 447 '5': '5', 448 '6': '6', 449 '7': '7', 450 '8': '8', 451 '9': '9', 452 'A': 'A', 453 'B': 'B', 454 'C': 'C', 455 'D': 'D', 456 'E': 'E', 457 'F': 'F', 458 'G': 'G', 459 'H': 'H', 460 'I': 'I', 461 'J': 'J', 462 'K': 'K', 463 'L': 'L', 464 'M': 'M', 465 'N': 'N', 466 'O': 'O', 467 'P': 'P', 468 'Q': 'Q', 469 'R': 'R', 470 'S': 'S', 471 'T': 'T', 472 'U': 'U', 473 'V': 'V', 474 'W': 'W', 475 'X': 'X', 476 'Y': 'Y', 477 'Z': 'Z', 478 'a': 'A', 479 'b': 'B', 480 'c': 'C', 481 'd': 'D', 482 'e': 'E', 483 'f': 'F', 484 'g': 'G', 485 'h': 'H', 486 'i': 'I', 487 'j': 'J', 488 'k': 'K', 489 'l': 'L', 490 'm': 'M', 491 'n': 'N', 492 'o': 'O', 493 'p': 'P', 494 'q': 'Q', 495 'r': 'R', 496 's': 'S', 497 't': 'T', 498 'u': 'U', 499 'v': 'V', 500 'w': 'W', 501 'x': 'X', 502 'y': 'Y', 503 'z': 'Z', 504 '-': '-', 505 '\uFF0D': '-', 506 '\u2010': '-', 507 '\u2011': '-', 508 '\u2012': '-', 509 '\u2013': '-', 510 '\u2014': '-', 511 '\u2015': '-', 512 '\u2212': '-', 513 '/': '/', 514 '\uFF0F': '/', 515 ' ': ' ', 516 '\u3000': ' ', 517 '\u2060': ' ', 518 '.': '.', 519 '\uFF0E': '.' 520}; 521 522 523/** 524 * Pattern that makes it easy to distinguish whether a region has a single 525 * international dialing prefix or not. If a region has a single international 526 * prefix (e.g. 011 in USA), it will be represented as a string that contains 527 * a sequence of ASCII digits, and possibly a tilde, which signals waiting for 528 * the tone. If there are multiple available international prefixes in a 529 * region, they will be represented as a regex string that always contains one 530 * or more characters that are not ASCII digits or a tilde. 531 * 532 * @const 533 * @type {!RegExp} 534 * @private 535 */ 536i18n.phonenumbers.PhoneNumberUtil.SINGLE_INTERNATIONAL_PREFIX_ = 537 /[\d]+(?:[~\u2053\u223C\uFF5E][\d]+)?/; 538 539 540/** 541 * Regular expression of acceptable punctuation found in phone numbers, used to 542 * find numbers in text and to decide what is a viable phone number. This 543 * excludes diallable characters. 544 * This consists of dash characters, white space characters, full stops, 545 * slashes, square brackets, parentheses and tildes. It also includes the letter 546 * 'x' as that is found as a placeholder for carrier information in some phone 547 * numbers. Full-width variants are also present. 548 * 549 * @const 550 * @type {string} 551 */ 552i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION = 553 '-x\u2010-\u2015\u2212\u30FC\uFF0D-\uFF0F \u00A0\u00AD\u200B\u2060\u3000' + 554 '()\uFF08\uFF09\uFF3B\uFF3D.\\[\\]/~\u2053\u223C\uFF5E'; 555 556 557/** 558 * Digits accepted in phone numbers (ascii, fullwidth, arabic-indic, and eastern 559 * arabic digits). 560 * 561 * @const 562 * @type {string} 563 * @private 564 */ 565i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ = 566 '0-9\uFF10-\uFF19\u0660-\u0669\u06F0-\u06F9'; 567 568 569/** 570 * We accept alpha characters in phone numbers, ASCII only, upper and lower 571 * case. 572 * 573 * @const 574 * @type {string} 575 * @private 576 */ 577i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ = 'A-Za-z'; 578 579 580/** 581 * @const 582 * @type {string} 583 * @private 584 */ 585i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ = '+\uFF0B'; 586 587 588/** 589 * @const 590 * @type {!RegExp} 591 */ 592i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_PATTERN = 593 new RegExp('[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']+'); 594 595 596/** 597 * @const 598 * @type {!RegExp} 599 * @package 600 */ 601i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN = 602 new RegExp('^[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']+'); 603 604 605/** 606 * @const 607 * @type {string} 608 * @private 609 */ 610i18n.phonenumbers.PhoneNumberUtil.SEPARATOR_PATTERN_ = 611 '[' + i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION + ']+'; 612 613 614/** 615 * @const 616 * @type {!RegExp} 617 */ 618i18n.phonenumbers.PhoneNumberUtil.CAPTURING_DIGIT_PATTERN = 619 new RegExp('([' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + '])'); 620 621 622/** 623 * Regular expression of acceptable characters that may start a phone number for 624 * the purposes of parsing. This allows us to strip away meaningless prefixes to 625 * phone numbers that may be mistakenly given to us. This consists of digits, 626 * the plus symbol and arabic-indic digits. This does not contain alpha 627 * characters, although they may be used later in the number. It also does not 628 * include other punctuation, as this will be stripped later during parsing and 629 * is of no information value when parsing a number. 630 * 631 * @const 632 * @type {!RegExp} 633 * @private 634 */ 635i18n.phonenumbers.PhoneNumberUtil.VALID_START_CHAR_PATTERN_ = 636 new RegExp('[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + 637 i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']'); 638 639 640/** 641 * Regular expression of characters typically used to start a second phone 642 * number for the purposes of parsing. This allows us to strip off parts of the 643 * number that are actually the start of another number, such as for: 644 * (530) 583-6985 x302/x2303 -> the second extension here makes this actually 645 * two phone numbers, (530) 583-6985 x302 and (530) 583-6985 x2303. We remove 646 * the second extension so that the first number is parsed correctly. 647 * 648 * @const 649 * @type {!RegExp} 650 * @private 651 */ 652i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_ = /[\\\/] *x/; 653 654 655/** 656 * Regular expression of trailing characters that we want to remove. We remove 657 * all characters that are not alpha or numerical characters. The hash character 658 * is retained here, as it may signify the previous block was an extension. 659 * 660 * @const 661 * @type {!RegExp} 662 * @private 663 */ 664i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_ = 665 new RegExp('[^' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + 666 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ + '#]+$'); 667 668 669/** 670 * We use this pattern to check if the phone number has at least three letters 671 * in it - if so, then we treat it as a number where some phone-number digits 672 * are represented by letters. 673 * 674 * @const 675 * @type {!RegExp} 676 * @private 677 */ 678i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_ = 679 /(?:.*?[A-Za-z]){3}.*/; 680 681 682/** 683 * Regular expression of viable phone numbers. This is location independent. 684 * Checks we have at least three leading digits, and only valid punctuation, 685 * alpha characters and digits in the phone number. Does not include extension 686 * data. The symbol 'x' is allowed here as valid punctuation since it is often 687 * used as a placeholder for carrier codes, for example in Brazilian phone 688 * numbers. We also allow multiple '+' characters at the start. 689 * Corresponds to the following: 690 * [digits]{minLengthNsn}| 691 * plus_sign* 692 * (([punctuation]|[star])*[digits]){3,}([punctuation]|[star]|[digits]|[alpha])* 693 * 694 * The first reg-ex is to allow short numbers (two digits long) to be parsed if 695 * they are entered as "15" etc, but only if there is no punctuation in them. 696 * The second expression restricts the number of digits to three or more, but 697 * then allows them to be in international form, and to have alpha-characters 698 * and punctuation. We split up the two reg-exes here and combine them when 699 * creating the reg-ex VALID_PHONE_NUMBER_PATTERN_ itself so we can prefix it 700 * with ^ and append $ to each branch. 701 * 702 * Note VALID_PUNCTUATION starts with a -, so must be the first in the range. 703 * 704 * @const 705 * @type {string} 706 * @private 707 */ 708i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_PHONE_NUMBER_PATTERN_ = 709 '[' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{' + 710 i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_ + '}'; 711 712 713/** 714 * See MIN_LENGTH_PHONE_NUMBER_PATTERN_ for a full description of this reg-exp. 715 * 716 * @const 717 * @type {string} 718 * @private 719 */ 720i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ = 721 '[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']*(?:[' + 722 i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION + 723 i18n.phonenumbers.PhoneNumberUtil.STAR_SIGN_ + ']*[' + 724 i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']){3,}[' + 725 i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION + 726 i18n.phonenumbers.PhoneNumberUtil.STAR_SIGN_ + 727 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ + 728 i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']*'; 729 730 731/** 732 * Default extension prefix to use when formatting. This will be put in front of 733 * any extension component of the number, after the main national number is 734 * formatted. For example, if you wish the default extension formatting to be 735 * ' extn: 3456', then you should specify ' extn: ' here as the default 736 * extension prefix. This can be overridden by region-specific preferences. 737 * 738 * @const 739 * @type {string} 740 * @private 741 */ 742i18n.phonenumbers.PhoneNumberUtil.DEFAULT_EXTN_PREFIX_ = ' ext. '; 743 744 745/** 746 * Helper method for constructing regular expressions for parsing. Creates 747 * an expression that captures up to max_length digits. 748 * 749 * @return {string} RegEx pattern to capture extension digits. 750 * @private 751 */ 752i18n.phonenumbers.PhoneNumberUtil.extnDigits_ = 753 function(maxLength) { 754 return ('([' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']' 755 + '{1,' + maxLength + '})'); 756}; 757 758/** 759 * Helper initialiser method to create the regular-expression pattern to match 760 * extensions. 761 * 762 * @return {string} RegEx pattern to capture extensions. 763 * @private 764 */ 765i18n.phonenumbers.PhoneNumberUtil.createExtnPattern_ = 766 function() { 767 // We cap the maximum length of an extension based on the ambiguity of the way 768 // the extension is prefixed. As per ITU, the officially allowed length for 769 // extensions is actually 40, but we don't support this since we haven't seen real 770 // examples and this introduces many false interpretations as the extension labels 771 // are not standardized. 772 /** @type {string} */ 773 var extLimitAfterExplicitLabel = '20'; 774 /** @type {string} */ 775 var extLimitAfterLikelyLabel = '15'; 776 /** @type {string} */ 777 var extLimitAfterAmbiguousChar = '9'; 778 /** @type {string} */ 779 var extLimitWhenNotSure = '6'; 780 781 /** @type {string} */ 782 var possibleSeparatorsBetweenNumberAndExtLabel = "[ \u00A0\\t,]*"; 783 // Optional full stop (.) or colon, followed by zero or more spaces/tabs/commas. 784 /** @type {string} */ 785 var possibleCharsAfterExtLabel = "[:\\.\uFF0E]?[ \u00A0\\t,-]*"; 786 /** @type {string} */ 787 var optionalExtnSuffix = "#?"; 788 789 // Here the extension is called out in more explicit way, i.e mentioning it obvious 790 // patterns like "ext.". 791 /** @type {string} */ 792 var explicitExtLabels = 793 "(?:e?xt(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45?\uFF58\uFF54\uFF4E?|\u0434\u043E\u0431|anexo)"; 794 // One-character symbols that can be used to indicate an extension, and less 795 // commonly used or more ambiguous extension labels. 796 /** @type {string} */ 797 var ambiguousExtLabels = "(?:[x\uFF58#\uFF03~\uFF5E]|int|\uFF49\uFF4E\uFF54)"; 798 // When extension is not separated clearly. 799 /** @type {string} */ 800 var ambiguousSeparator = "[- ]+"; 801 // This is the same as possibleSeparatorsBetweenNumberAndExtLabel, but not matching 802 // comma as extension label may have it. 803 /** @type {string} */ 804 var possibleSeparatorsNumberExtLabelNoComma = "[ \u00A0\\t]*"; 805 // ",," is commonly used for auto dialling the extension when connected. First 806 // comma is matched through possibleSeparatorsBetweenNumberAndExtLabel, so we do 807 // not repeat it here. Semi-colon works in Iphone and Android also to pop up a 808 // button with the extension number following. 809 /** @type {string} */ 810 var autoDiallingAndExtLabelsFound = "(?:,{2}|;)"; 811 812 /** @type {string} */ 813 var rfcExtn = i18n.phonenumbers.PhoneNumberUtil.RFC3966_EXTN_PREFIX_ 814 + i18n.phonenumbers.PhoneNumberUtil.extnDigits_(extLimitAfterExplicitLabel); 815 /** @type {string} */ 816 var explicitExtn = possibleSeparatorsBetweenNumberAndExtLabel + explicitExtLabels 817 + possibleCharsAfterExtLabel 818 + i18n.phonenumbers.PhoneNumberUtil.extnDigits_(extLimitAfterExplicitLabel) 819 + optionalExtnSuffix; 820 /** @type {string} */ 821 var ambiguousExtn = possibleSeparatorsBetweenNumberAndExtLabel + ambiguousExtLabels 822 + possibleCharsAfterExtLabel 823 + i18n.phonenumbers.PhoneNumberUtil.extnDigits_(extLimitAfterAmbiguousChar) 824 + optionalExtnSuffix; 825 /** @type {string} */ 826 var americanStyleExtnWithSuffix = ambiguousSeparator 827 + i18n.phonenumbers.PhoneNumberUtil.extnDigits_(extLimitWhenNotSure) + "#"; 828 829 /** @type {string} */ 830 var autoDiallingExtn = possibleSeparatorsNumberExtLabelNoComma 831 + autoDiallingAndExtLabelsFound + possibleCharsAfterExtLabel 832 + i18n.phonenumbers.PhoneNumberUtil.extnDigits_(extLimitAfterLikelyLabel) 833 + optionalExtnSuffix; 834 /** @type {string} */ 835 var onlyCommasExtn = possibleSeparatorsNumberExtLabelNoComma 836 + "(?:,)+" + possibleCharsAfterExtLabel 837 + i18n.phonenumbers.PhoneNumberUtil.extnDigits_(extLimitAfterAmbiguousChar) 838 + optionalExtnSuffix; 839 840 // The first regular expression covers RFC 3966 format, where the extension is added 841 // using ";ext=". The second more generic where extension is mentioned with explicit 842 // labels like "ext:". In both the above cases we allow more numbers in extension than 843 // any other extension labels. The third one captures when single character extension 844 // labels or less commonly used labels are used. In such cases we capture fewer 845 // extension digits in order to reduce the chance of falsely interpreting two 846 // numbers beside each other as a number + extension. The fourth one covers the 847 // special case of American numbers where the extension is written with a hash 848 // at the end, such as "- 503#". The fifth one is exclusively for extension 849 // autodialling formats which are used when dialling and in this case we accept longer 850 // extensions. The last one is more liberal on the number of commas that acts as 851 // extension labels, so we have a strict cap on the number of digits in such extensions. 852 return rfcExtn + "|" 853 + explicitExtn + "|" 854 + ambiguousExtn + "|" 855 + americanStyleExtnWithSuffix + "|" 856 + autoDiallingExtn + "|" 857 + onlyCommasExtn; 858}; 859 860 861/** 862 * Regexp of all known extension prefixes used by different regions followed by 863 * 1 or more valid digits, for use when parsing. 864 * 865 * @const 866 * @type {!RegExp} 867 * @private 868 */ 869i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_ = 870 new RegExp('(?:' + 871 i18n.phonenumbers.PhoneNumberUtil.createExtnPattern_() + 872 ')$', 'i'); 873 874 875/** 876 * We append optionally the extension pattern to the end here, as a valid phone 877 * number may have an extension prefix appended, followed by 1 or more digits. 878 * 879 * @const 880 * @type {!RegExp} 881 * @private 882 */ 883i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_PATTERN_ = 884 new RegExp( 885 '^' + 886 i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_PHONE_NUMBER_PATTERN_ + 887 '$|' + 888 '^' + i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ + 889 '(?:' + i18n.phonenumbers.PhoneNumberUtil.createExtnPattern_() + 890 ')?' + '$', 'i'); 891 892 893/** 894 * @const 895 * @type {!RegExp} 896 * @private 897 */ 898i18n.phonenumbers.PhoneNumberUtil.NON_DIGITS_PATTERN_ = /\D+/; 899 900 901/** 902 * This was originally set to $1 but there are some countries for which the 903 * first group is not used in the national pattern (e.g. Argentina) so the $1 904 * group does not match correctly. Therefore, we use \d, so that the first 905 * group actually used in the pattern will be matched. 906 * @const 907 * @type {!RegExp} 908 * @private 909 */ 910i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_ = /(\$\d)/; 911 912 913/** 914 * @const 915 * @type {!RegExp} 916 * @private 917 */ 918i18n.phonenumbers.PhoneNumberUtil.NP_PATTERN_ = /\$NP/; 919 920 921/** 922 * @const 923 * @type {!RegExp} 924 * @private 925 */ 926i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_ = /\$FG/; 927 928 929/** 930 * @const 931 * @type {!RegExp} 932 * @private 933 */ 934i18n.phonenumbers.PhoneNumberUtil.CC_PATTERN_ = /\$CC/; 935 936 937/** 938 * A pattern that is used to determine if the national prefix formatting rule 939 * has the first group only, i.e., does not start with the national prefix. 940 * Note that the pattern explicitly allows for unbalanced parentheses. 941 * @const 942 * @type {!RegExp} 943 * @private 944 */ 945i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_ONLY_PREFIX_PATTERN_ = 946 /^\(?\$1\)?$/; 947 948 949/** 950 * @const 951 * @type {string} 952 */ 953i18n.phonenumbers.PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY = '001'; 954 955 956/** 957 * INTERNATIONAL and NATIONAL formats are consistent with the definition in 958 * ITU-T Recommendation E123. However we follow local conventions such as 959 * using '-' instead of whitespace as separators. For example, the number of the 960 * Google Switzerland office will be written as '+41 44 668 1800' in 961 * INTERNATIONAL format, and as '044 668 1800' in NATIONAL format. E164 format 962 * is as per INTERNATIONAL format but with no formatting applied, e.g. 963 * '+41446681800'. RFC3966 is as per INTERNATIONAL format, but with all spaces 964 * and other separating symbols replaced with a hyphen, and with any phone 965 * number extension appended with ';ext='. It also will have a prefix of 'tel:' 966 * added, e.g. 'tel:+41-44-668-1800'. 967 * 968 * Note: If you are considering storing the number in a neutral format, you are 969 * highly advised to use the PhoneNumber class. 970 * @enum {number} 971 */ 972i18n.phonenumbers.PhoneNumberFormat = { 973 E164: 0, 974 INTERNATIONAL: 1, 975 NATIONAL: 2, 976 RFC3966: 3 977}; 978 979 980/** 981 * Type of phone numbers. 982 * 983 * @enum {number} 984 */ 985i18n.phonenumbers.PhoneNumberType = { 986 FIXED_LINE: 0, 987 MOBILE: 1, 988 // In some regions (e.g. the USA), it is impossible to distinguish between 989 // fixed-line and mobile numbers by looking at the phone number itself. 990 FIXED_LINE_OR_MOBILE: 2, 991 // Freephone lines 992 TOLL_FREE: 3, 993 PREMIUM_RATE: 4, 994 // The cost of this call is shared between the caller and the recipient, and 995 // is hence typically less than PREMIUM_RATE calls. See 996 // http://en.wikipedia.org/wiki/Shared_Cost_Service for more information. 997 SHARED_COST: 5, 998 // Voice over IP numbers. This includes TSoIP (Telephony Service over IP). 999 VOIP: 6, 1000 // A personal number is associated with a particular person, and may be routed 1001 // to either a MOBILE or FIXED_LINE number. Some more information can be found 1002 // here: http://en.wikipedia.org/wiki/Personal_Numbers 1003 PERSONAL_NUMBER: 7, 1004 PAGER: 8, 1005 // Used for 'Universal Access Numbers' or 'Company Numbers'. They may be 1006 // further routed to specific offices, but allow one number to be used for a 1007 // company. 1008 UAN: 9, 1009 // Used for 'Voice Mail Access Numbers'. 1010 VOICEMAIL: 10, 1011 // A phone number is of type UNKNOWN when it does not fit any of the known 1012 // patterns for a specific region. 1013 UNKNOWN: -1 1014}; 1015 1016 1017/** 1018 * Types of phone number matches. See detailed description beside the 1019 * isNumberMatch() method. 1020 * 1021 * @enum {number} 1022 */ 1023i18n.phonenumbers.PhoneNumberUtil.MatchType = { 1024 NOT_A_NUMBER: 0, 1025 NO_MATCH: 1, 1026 SHORT_NSN_MATCH: 2, 1027 NSN_MATCH: 3, 1028 EXACT_MATCH: 4 1029}; 1030 1031 1032/** 1033 * Possible outcomes when testing if a PhoneNumber is possible. 1034 * 1035 * @enum {number} 1036 */ 1037i18n.phonenumbers.PhoneNumberUtil.ValidationResult = { 1038 /** The number length matches that of valid numbers for this region. */ 1039 IS_POSSIBLE: 0, 1040 /** 1041 * The number length matches that of local numbers for this region only (i.e. 1042 * numbers that may be able to be dialled within an area, but do not have all 1043 * the information to be dialled from anywhere inside or outside the country). 1044 */ 1045 IS_POSSIBLE_LOCAL_ONLY: 4, 1046 /** The number has an invalid country calling code. */ 1047 INVALID_COUNTRY_CODE: 1, 1048 /** The number is shorter than all valid numbers for this region. */ 1049 TOO_SHORT: 2, 1050 /** 1051 * The number is longer than the shortest valid numbers for this region, 1052 * shorter than the longest valid numbers for this region, and does not itself 1053 * have a number length that matches valid numbers for this region. 1054 * This can also be returned in the case where 1055 * isPossibleNumberForTypeWithReason was called, and there are no numbers of 1056 * this type at all for this region. 1057 */ 1058 INVALID_LENGTH: 5, 1059 /** The number is longer than all valid numbers for this region. */ 1060 TOO_LONG: 3 1061}; 1062 1063 1064/** 1065 * Attempts to extract a possible number from the string passed in. This 1066 * currently strips all leading characters that cannot be used to start a phone 1067 * number. Characters that can be used to start a phone number are defined in 1068 * the VALID_START_CHAR_PATTERN. If none of these characters are found in the 1069 * number passed in, an empty string is returned. This function also attempts to 1070 * strip off any alternative extensions or endings if two or more are present, 1071 * such as in the case of: (530) 583-6985 x302/x2303. The second extension here 1072 * makes this actually two phone numbers, (530) 583-6985 x302 and (530) 583-6985 1073 * x2303. We remove the second extension so that the first number is parsed 1074 * correctly. 1075 * 1076 * @param {string} number the string that might contain a phone number. 1077 * @return {string} the number, stripped of any non-phone-number prefix (such as 1078 * 'Tel:') or an empty string if no character used to start phone numbers 1079 * (such as + or any digit) is found in the number. 1080 */ 1081i18n.phonenumbers.PhoneNumberUtil.extractPossibleNumber = function(number) { 1082 /** @type {string} */ 1083 var possibleNumber; 1084 1085 /** @type {number} */ 1086 var start = number 1087 .search(i18n.phonenumbers.PhoneNumberUtil.VALID_START_CHAR_PATTERN_); 1088 if (start >= 0) { 1089 possibleNumber = number.substring(start); 1090 // Remove trailing non-alpha non-numerical characters. 1091 possibleNumber = possibleNumber.replace( 1092 i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_, ''); 1093 1094 // Check for extra numbers at the end. 1095 /** @type {number} */ 1096 var secondNumberStart = possibleNumber 1097 .search(i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_); 1098 if (secondNumberStart >= 0) { 1099 possibleNumber = possibleNumber.substring(0, secondNumberStart); 1100 } 1101 } else { 1102 possibleNumber = ''; 1103 } 1104 return possibleNumber; 1105}; 1106 1107 1108/** 1109 * Checks to see if the string of characters could possibly be a phone number at 1110 * all. At the moment, checks to see that the string begins with at least 2 1111 * digits, ignoring any punctuation commonly found in phone numbers. This method 1112 * does not require the number to be normalized in advance - but does assume 1113 * that leading non-number symbols have been removed, such as by the method 1114 * extractPossibleNumber. 1115 * 1116 * @param {string} number string to be checked for viability as a phone number. 1117 * @return {boolean} true if the number could be a phone number of some sort, 1118 * otherwise false. 1119 */ 1120i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber = function(number) { 1121 if (number.length < i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) { 1122 return false; 1123 } 1124 return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely( 1125 i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_PATTERN_, number); 1126}; 1127 1128 1129/** 1130 * Normalizes a string of characters representing a phone number. This performs 1131 * the following conversions: 1132 * Punctuation is stripped. 1133 * For ALPHA/VANITY numbers: 1134 * Letters are converted to their numeric representation on a telephone 1135 * keypad. The keypad used here is the one defined in ITU Recommendation 1136 * E.161. This is only done if there are 3 or more letters in the number, 1137 * to lessen the risk that such letters are typos. 1138 * For other numbers: 1139 * Wide-ascii digits are converted to normal ASCII (European) digits. 1140 * Arabic-Indic numerals are converted to European numerals. 1141 * Spurious alpha characters are stripped. 1142 * 1143 * @param {string} number a string of characters representing a phone number. 1144 * @return {string} the normalized string version of the phone number. 1145 */ 1146i18n.phonenumbers.PhoneNumberUtil.normalize = function(number) { 1147 if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely( 1148 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_, number)) { 1149 return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number, 1150 i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_, true); 1151 } else { 1152 return i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly(number); 1153 } 1154}; 1155 1156 1157/** 1158 * Normalizes a string of characters representing a phone number. This is a 1159 * wrapper for normalize(String number) but does in-place normalization of the 1160 * StringBuffer provided. 1161 * 1162 * @param {!goog.string.StringBuffer} number a StringBuffer of characters 1163 * representing a phone number that will be normalized in place. 1164 * @private 1165 */ 1166i18n.phonenumbers.PhoneNumberUtil.normalizeSB_ = function(number) { 1167 /** @type {string} */ 1168 var normalizedNumber = i18n.phonenumbers.PhoneNumberUtil.normalize(number 1169 .toString()); 1170 number.clear(); 1171 number.append(normalizedNumber); 1172}; 1173 1174 1175/** 1176 * Normalizes a string of characters representing a phone number. This converts 1177 * wide-ascii and arabic-indic numerals to European numerals, and strips 1178 * punctuation and alpha characters. 1179 * 1180 * @param {string} number a string of characters representing a phone number. 1181 * @return {string} the normalized string version of the phone number. 1182 */ 1183i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly = function(number) { 1184 return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number, 1185 i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS, true); 1186}; 1187 1188 1189/** 1190 * Normalizes a string of characters representing a phone number. This strips 1191 * all characters which are not diallable on a mobile phone keypad (including 1192 * all non-ASCII digits). 1193 * 1194 * @param {string} number a string of characters representing a phone number. 1195 * @return {string} the normalized string version of the phone number. 1196 */ 1197i18n.phonenumbers.PhoneNumberUtil.normalizeDiallableCharsOnly = 1198 function(number) { 1199 1200 return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number, 1201 i18n.phonenumbers.PhoneNumberUtil.DIALLABLE_CHAR_MAPPINGS_, 1202 true /* remove non matches */); 1203}; 1204 1205 1206/** 1207 * Converts all alpha characters in a number to their respective digits on a 1208 * keypad, but retains existing formatting. Also converts wide-ascii digits to 1209 * normal ascii digits, and converts Arabic-Indic numerals to European numerals. 1210 * 1211 * @param {string} number a string of characters representing a phone number. 1212 * @return {string} the normalized string version of the phone number. 1213 */ 1214i18n.phonenumbers.PhoneNumberUtil.convertAlphaCharactersInNumber = 1215 function(number) { 1216 1217 return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number, 1218 i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_, false); 1219}; 1220 1221 1222/** 1223 * Gets the length of the geographical area code from the 1224 * {@code national_number} field of the PhoneNumber object passed in, so that 1225 * clients could use it to split a national significant number into geographical 1226 * area code and subscriber number. It works in such a way that the resultant 1227 * subscriber number should be diallable, at least on some devices. An example 1228 * of how this could be used: 1229 * 1230 * <pre> 1231 * var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance(); 1232 * var number = phoneUtil.parse('16502530000', 'US'); 1233 * var nationalSignificantNumber = 1234 * phoneUtil.getNationalSignificantNumber(number); 1235 * var areaCode; 1236 * var subscriberNumber; 1237 * 1238 * var areaCodeLength = phoneUtil.getLengthOfGeographicalAreaCode(number); 1239 * if (areaCodeLength > 0) { 1240 * areaCode = nationalSignificantNumber.substring(0, areaCodeLength); 1241 * subscriberNumber = nationalSignificantNumber.substring(areaCodeLength); 1242 * } else { 1243 * areaCode = ''; 1244 * subscriberNumber = nationalSignificantNumber; 1245 * } 1246 * </pre> 1247 * 1248 * N.B.: area code is a very ambiguous concept, so the I18N team generally 1249 * recommends against using it for most purposes, but recommends using the more 1250 * general {@code national_number} instead. Read the following carefully before 1251 * deciding to use this method: 1252 * <ul> 1253 * <li> geographical area codes change over time, and this method honors those 1254 * changes; therefore, it doesn't guarantee the stability of the result it 1255 * produces. 1256 * <li> subscriber numbers may not be diallable from all devices (notably 1257 * mobile devices, which typically requires the full national_number to be 1258 * dialled in most regions). 1259 * <li> most non-geographical numbers have no area codes, including numbers 1260 * from non-geographical entities. 1261 * <li> some geographical numbers have no area codes. 1262 * </ul> 1263 * 1264 * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for 1265 * which clients want to know the length of the area code. 1266 * @return {number} the length of area code of the PhoneNumber object passed in. 1267 */ 1268i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfGeographicalAreaCode = 1269 function(number) { 1270 /** @type {i18n.phonenumbers.PhoneMetadata} */ 1271 var metadata = this.getMetadataForRegion(this.getRegionCodeForNumber(number)); 1272 if (metadata == null) { 1273 return 0; 1274 } 1275 // If a country doesn't use a national prefix, and this number doesn't have 1276 // an Italian leading zero, we assume it is a closed dialling plan with no 1277 // area codes. 1278 if (!metadata.hasNationalPrefix() && !number.hasItalianLeadingZero()) { 1279 return 0; 1280 } 1281 1282 if (!this.isNumberGeographical(number)) { 1283 return 0; 1284 } 1285 1286 return this.getLengthOfNationalDestinationCode(number); 1287}; 1288 1289 1290/** 1291 * Gets the length of the national destination code (NDC) from the PhoneNumber 1292 * object passed in, so that clients could use it to split a national 1293 * significant number into NDC and subscriber number. The NDC of a phone number 1294 * is normally the first group of digit(s) right after the country calling code 1295 * when the number is formatted in the international format, if there is a 1296 * subscriber number part that follows. 1297 * 1298 * N.B.: similar to an area code, not all numbers have an NDC! 1299 * 1300 * An example of how this could be used: 1301 * 1302 * <pre> 1303 * var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance(); 1304 * var number = phoneUtil.parse('18002530000', 'US'); 1305 * var nationalSignificantNumber = 1306 * phoneUtil.getNationalSignificantNumber(number); 1307 * var nationalDestinationCode; 1308 * var subscriberNumber; 1309 * 1310 * var nationalDestinationCodeLength = 1311 * phoneUtil.getLengthOfNationalDestinationCode(number); 1312 * if (nationalDestinationCodeLength > 0) { 1313 * nationalDestinationCode = 1314 * nationalSignificantNumber.substring(0, nationalDestinationCodeLength); 1315 * subscriberNumber = 1316 * nationalSignificantNumber.substring(nationalDestinationCodeLength); 1317 * } else { 1318 * nationalDestinationCode = ''; 1319 * subscriberNumber = nationalSignificantNumber; 1320 * } 1321 * </pre> 1322 * 1323 * Refer to the unittests to see the difference between this function and 1324 * {@link #getLengthOfGeographicalAreaCode}. 1325 * 1326 * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for 1327 * which clients want to know the length of the NDC. 1328 * @return {number} the length of NDC of the PhoneNumber object passed in, which 1329 * could be zero. 1330 */ 1331i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfNationalDestinationCode = 1332 function(number) { 1333 1334 /** @type {i18n.phonenumbers.PhoneNumber} */ 1335 var copiedProto; 1336 if (number.hasExtension()) { 1337 // We don't want to alter the proto given to us, but we don't want to 1338 // include the extension when we format it, so we copy it and clear the 1339 // extension here. 1340 copiedProto = number.clone(); 1341 copiedProto.clearExtension(); 1342 } else { 1343 copiedProto = number; 1344 } 1345 1346 /** @type {string} */ 1347 var nationalSignificantNumber = this.format(copiedProto, 1348 i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL); 1349 /** @type {!Array.<string>} */ 1350 var numberGroups = nationalSignificantNumber.split( 1351 i18n.phonenumbers.PhoneNumberUtil.NON_DIGITS_PATTERN_); 1352 // The pattern will start with '+COUNTRY_CODE ' so the first group will always 1353 // be the empty string (before the + symbol) and the second group will be the 1354 // country calling code. The third group will be area code if it is not the 1355 // last group. 1356 // NOTE: On IE the first group that is supposed to be the empty string does 1357 // not appear in the array of number groups... so make the result on non-IE 1358 // browsers to be that of IE. 1359 if (numberGroups[0].length == 0) { 1360 numberGroups.shift(); 1361 } 1362 if (numberGroups.length <= 2) { 1363 return 0; 1364 } 1365 1366 if (this.getNumberType(number) == i18n.phonenumbers.PhoneNumberType.MOBILE) { 1367 // For example Argentinian mobile numbers, when formatted in the 1368 // international format, are in the form of +54 9 NDC XXXX.... As a result, 1369 // we take the length of the third group (NDC) and add the length of the 1370 // mobile token, which also forms part of the national significant number. 1371 // This assumes that the mobile token is always formatted separately from 1372 // the rest of the phone number. 1373 /** @type {string} */ 1374 var mobileToken = i18n.phonenumbers.PhoneNumberUtil.getCountryMobileToken( 1375 number.getCountryCodeOrDefault()); 1376 if (mobileToken != '') { 1377 return numberGroups[2].length + mobileToken.length; 1378 } 1379 } 1380 return numberGroups[1].length; 1381}; 1382 1383 1384/** 1385 * Returns the mobile token for the provided country calling code if it has 1386 * one, otherwise returns an empty string. A mobile token is a number inserted 1387 * before the area code when dialing a mobile number from that country from 1388 * abroad. 1389 * 1390 * @param {number} countryCallingCode the country calling code for which we 1391 * want the mobile token. 1392 * @return {string} the mobile token for the given country calling code. 1393 */ 1394i18n.phonenumbers.PhoneNumberUtil.getCountryMobileToken = 1395 function(countryCallingCode) { 1396 return i18n.phonenumbers.PhoneNumberUtil.MOBILE_TOKEN_MAPPINGS_[ 1397 countryCallingCode] || ''; 1398}; 1399 1400 1401/** 1402 * Returns all regions the library has metadata for. 1403 * 1404 * @return {!Array.<string>} the two-letter region codes for every geographical 1405 * region the library supports. 1406 */ 1407i18n.phonenumbers.PhoneNumberUtil.prototype.getSupportedRegions = function() { 1408 return Object.keys(i18n.phonenumbers.metadata.countryToMetadata) 1409 .filter(function(regionCode) { 1410 return isNaN(regionCode); 1411 }); 1412}; 1413 1414 1415/** 1416 * Returns all global network calling codes the library has metadata for. 1417 * 1418 * @return {!Array.<number>} the country calling codes for every 1419 * non-geographical entity the library supports. 1420 */ 1421i18n.phonenumbers.PhoneNumberUtil.prototype 1422 .getSupportedGlobalNetworkCallingCodes = function() { 1423 var callingCodesAsStrings = 1424 Object.keys(i18n.phonenumbers.metadata.countryToMetadata) 1425 .filter(function(regionCode) { 1426 return !isNaN(regionCode); 1427 }); 1428 return callingCodesAsStrings.map(function(callingCode) { 1429 return parseInt(callingCode, 10); 1430 }); 1431}; 1432 1433 1434/** 1435 * Returns all country calling codes the library has metadata for, covering 1436 * both non-geographical entities (global network calling codes) and those used 1437 * for geographical entities. This could be used to populate a drop-down box of 1438 * country calling codes for a phone-number widget, for instance. 1439 * 1440 * @return {!Array.<number>} the country calling codes for every geographical 1441 * and non-geographical entity the library supports. 1442 */ 1443i18n.phonenumbers.PhoneNumberUtil.prototype.getSupportedCallingCodes = 1444 function() { 1445 var countryCodesAsStrings = 1446 Object.keys(i18n.phonenumbers.metadata.countryCodeToRegionCodeMap); 1447 return [ 1448 ...this.getSupportedGlobalNetworkCallingCodes(), 1449 ...countryCodesAsStrings.map(function(callingCode) { 1450 return parseInt(callingCode, 10); 1451 }) 1452 ]; 1453}; 1454 1455 1456/** 1457 * Returns true if there is any possibleLength data set for a particular 1458 * PhoneNumberDesc. 1459 * 1460 * @param {i18n.phonenumbers.PhoneNumberDesc} desc 1461 * @return {boolean} 1462 * @private 1463 */ 1464i18n.phonenumbers.PhoneNumberUtil.descHasPossibleNumberData_ = function(desc) { 1465 // If this is empty, it means numbers of this type inherit from the "general 1466 // desc" -> the value "-1" means that no numbers exist for this type. 1467 return desc != null && 1468 (desc.possibleLengthCount() != 1 || desc.possibleLengthArray()[0] != -1); 1469}; 1470 1471 1472/** 1473 * Returns true if there is any data set for a particular PhoneNumberDesc. 1474 * 1475 * @param {i18n.phonenumbers.PhoneNumberDesc} desc 1476 * @return {boolean} 1477 * @private 1478 */ 1479i18n.phonenumbers.PhoneNumberUtil.descHasData_ = function(desc) { 1480 // Checking most properties since we don't know what's present, since a 1481 // custom build may have stripped just one of them (e.g. liteBuild strips 1482 // exampleNumber). We don't bother checking the possibleLengthsLocalOnly, 1483 // since if this is the only thing that's present we don't really support the 1484 // type at all: no type-specific methods will work with only this data. 1485 return desc != null && (desc.hasExampleNumber() || 1486 i18n.phonenumbers.PhoneNumberUtil.descHasPossibleNumberData_(desc) || 1487 desc.hasNationalNumberPattern()); 1488}; 1489 1490 1491/** 1492 * Returns the types we have metadata for based on the PhoneMetadata object 1493 * passed in. 1494 * 1495 * @param {!i18n.phonenumbers.PhoneMetadata} metadata 1496 * @return {!Array.<i18n.phonenumbers.PhoneNumberType>} the types supported 1497 * based on the metadata object passed in. 1498 * @private 1499 */ 1500i18n.phonenumbers.PhoneNumberUtil.getSupportedTypesForMetadata_ = 1501 function(metadata) { 1502 /** @type {!Array.<i18n.phonenumbers.PhoneNumberType>} */ 1503 var types = []; 1504 goog.object.forEach(i18n.phonenumbers.PhoneNumberType, 1505 function(type) { 1506 if (type == i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE || 1507 type == i18n.phonenumbers.PhoneNumberType.UNKNOWN) { 1508 // Never return FIXED_LINE_OR_MOBILE (it is a convenience type, and 1509 // represents that a particular number type can't be determined) or 1510 // UNKNOWN (the non-type). 1511 return; 1512 } 1513 /** @type {i18n.phonenumbers.PhoneNumberDesc} */ 1514 var desc = i18n.phonenumbers.PhoneNumberUtil.getNumberDescByType_( 1515 metadata, type); 1516 if (i18n.phonenumbers.PhoneNumberUtil.descHasData_(desc)) { 1517 types.push(type); 1518 } 1519 }); 1520 return types; 1521}; 1522 1523 1524/** 1525 * Returns the types for a given region which the library has metadata for. 1526 * Will not include FIXED_LINE_OR_MOBILE (if numbers for this non-geographical 1527 * entity could be classified as FIXED_LINE_OR_MOBILE, both FIXED_LINE and 1528 * MOBILE would be present) and UNKNOWN. 1529 * 1530 * No types will be returned for invalid or unknown region codes. 1531 * 1532 * @param {?string} regionCode 1533 * @return {!Array.<i18n.phonenumbers.PhoneNumberType>} the types for every 1534 * region the library supports. 1535 */ 1536i18n.phonenumbers.PhoneNumberUtil.prototype.getSupportedTypesForRegion = 1537 function(regionCode) { 1538 if (!this.isValidRegionCode_(regionCode)) { 1539 return []; 1540 } 1541 return i18n.phonenumbers.PhoneNumberUtil.getSupportedTypesForMetadata_( 1542 /** @type {!i18n.phonenumbers.PhoneMetadata} */ ( 1543 this.getMetadataForRegion(regionCode))); 1544}; 1545 1546 1547/** 1548 * Returns the types for a country-code belonging to a non-geographical entity 1549 * which the library has metadata for. Will not include FIXED_LINE_OR_MOBILE 1550 * (instead both FIXED_LINE and FIXED_LINE_OR_MOBILE (if numbers for this 1551 * non-geographical entity could be classified as FIXED_LINE_OR_MOBILE, both 1552 * FIXED_LINE and MOBILE would be present) and UNKNOWN. 1553 * 1554 * No types will be returned for country calling codes that do not map to a 1555 * known non-geographical entity. 1556 * 1557 * @param {number} countryCallingCode 1558 * @return {!Array.<i18n.phonenumbers.PhoneNumberType>} the types for every 1559 * non-geographical entity the library supports. 1560 */ 1561i18n.phonenumbers.PhoneNumberUtil.prototype.getSupportedTypesForNonGeoEntity = 1562 function(countryCallingCode) { 1563 /** @type {i18n.phonenumbers.PhoneMetadata} */ 1564 var metadata = this.getMetadataForNonGeographicalRegion(countryCallingCode); 1565 if (metadata == null) { 1566 return []; 1567 } 1568 return i18n.phonenumbers.PhoneNumberUtil.getSupportedTypesForMetadata_( 1569 /** @type {!i18n.phonenumbers.PhoneMetadata} */ (metadata)); 1570}; 1571 1572 1573/** 1574 * Normalizes a string of characters representing a phone number by replacing 1575 * all characters found in the accompanying map with the values therein, and 1576 * stripping all other characters if removeNonMatches is true. 1577 * 1578 * @param {string} number a string of characters representing a phone number. 1579 * @param {!Object.<string, string>} normalizationReplacements a mapping of 1580 * characters to what they should be replaced by in the normalized version 1581 * of the phone number. 1582 * @param {boolean} removeNonMatches indicates whether characters that are not 1583 * able to be replaced should be stripped from the number. If this is false, 1584 * they will be left unchanged in the number. 1585 * @return {string} the normalized string version of the phone number. 1586 * @private 1587 */ 1588i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_ = 1589 function(number, normalizationReplacements, removeNonMatches) { 1590 1591 /** @type {!goog.string.StringBuffer} */ 1592 var normalizedNumber = new goog.string.StringBuffer(); 1593 /** @type {string} */ 1594 var character; 1595 /** @type {string} */ 1596 var newDigit; 1597 /** @type {number} */ 1598 var numberLength = number.length; 1599 for (var i = 0; i < numberLength; ++i) { 1600 character = number.charAt(i); 1601 newDigit = normalizationReplacements[character.toUpperCase()]; 1602 if (newDigit != null) { 1603 normalizedNumber.append(newDigit); 1604 } else if (!removeNonMatches) { 1605 normalizedNumber.append(character); 1606 } 1607 // If neither of the above are true, we remove this character. 1608 } 1609 return normalizedNumber.toString(); 1610}; 1611 1612 1613/** 1614 * Helper function to check if the national prefix formatting rule has the first 1615 * group only, i.e., does not start with the national prefix. 1616 * 1617 * @param {string} nationalPrefixFormattingRule The formatting rule for the 1618 * national prefix. 1619 * @return {boolean} true if the national prefix formatting rule has the first 1620 * group only. 1621 */ 1622i18n.phonenumbers.PhoneNumberUtil.prototype.formattingRuleHasFirstGroupOnly = 1623 function(nationalPrefixFormattingRule) { 1624 return nationalPrefixFormattingRule.length == 0 || 1625 i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_ONLY_PREFIX_PATTERN_. 1626 test(nationalPrefixFormattingRule); 1627}; 1628 1629 1630/** 1631 * Tests whether a phone number has a geographical association. It checks if the 1632 * number is associated with a certain region in the country to which it 1633 * belongs. Note that this doesn't verify if the number is actually in use. 1634 * 1635 * @param {i18n.phonenumbers.PhoneNumber} phoneNumber The phone number to test. 1636 * @return {boolean} true if the phone number has a geographical association. 1637 */ 1638i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberGeographical = 1639 function(phoneNumber) { 1640 /** @type {i18n.phonenumbers.PhoneNumberType} */ 1641 var numberType = this.getNumberType(phoneNumber); 1642 1643 return numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE || 1644 numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE || 1645 (i18n.phonenumbers.PhoneNumberUtil.GEO_MOBILE_COUNTRIES_.includes( 1646 phoneNumber.getCountryCodeOrDefault()) && 1647 numberType == i18n.phonenumbers.PhoneNumberType.MOBILE); 1648}; 1649 1650 1651/** 1652 * Helper function to check region code is not unknown or null. 1653 * 1654 * @param {?string} regionCode the CLDR two-letter region code. 1655 * @return {boolean} true if region code is valid. 1656 * @private 1657 */ 1658i18n.phonenumbers.PhoneNumberUtil.prototype.isValidRegionCode_ = 1659 function(regionCode) { 1660 1661 // In Java we check whether the regionCode is contained in supportedRegions 1662 // that is built out of all the values of countryCallingCodeToRegionCodeMap 1663 // (countryCodeToRegionCodeMap in JS) minus REGION_CODE_FOR_NON_GEO_ENTITY. 1664 // In JS we check whether the regionCode is contained in the keys of 1665 // countryToMetadata but since for non-geographical country calling codes 1666 // (e.g. +800) we use the country calling codes instead of the region code as 1667 // key in the map we have to make sure regionCode is not a number to prevent 1668 // returning true for non-geographical country calling codes. 1669 return regionCode != null && 1670 isNaN(regionCode) && 1671 regionCode.toUpperCase() in i18n.phonenumbers.metadata.countryToMetadata; 1672}; 1673 1674 1675/** 1676 * Helper function to check the country calling code is valid. 1677 * 1678 * @param {number} countryCallingCode the country calling code. 1679 * @return {boolean} true if country calling code code is valid. 1680 * @private 1681 */ 1682i18n.phonenumbers.PhoneNumberUtil.prototype.hasValidCountryCallingCode_ = 1683 function(countryCallingCode) { 1684 1685 return countryCallingCode in 1686 i18n.phonenumbers.metadata.countryCodeToRegionCodeMap; 1687}; 1688 1689 1690/** 1691 * Formats a phone number in the specified format using default rules. Note that 1692 * this does not promise to produce a phone number that the user can dial from 1693 * where they are - although we do format in either 'national' or 1694 * 'international' format depending on what the client asks for, we do not 1695 * currently support a more abbreviated format, such as for users in the same 1696 * 'area' who could potentially dial the number without area code. Note that if 1697 * the phone number has a country calling code of 0 or an otherwise invalid 1698 * country calling code, we cannot work out which formatting rules to apply so 1699 * we return the national significant number with no formatting applied. 1700 * 1701 * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be 1702 * formatted. 1703 * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the 1704 * phone number should be formatted into. 1705 * @return {string} the formatted phone number. 1706 */ 1707i18n.phonenumbers.PhoneNumberUtil.prototype.format = 1708 function(number, numberFormat) { 1709 1710 if (number.getNationalNumber() == 0 && number.hasRawInput()) { 1711 // Unparseable numbers that kept their raw input just use that. 1712 // This is the only case where a number can be formatted as E164 without a 1713 // leading '+' symbol (but the original number wasn't parseable anyway). 1714 // TODO: Consider removing the 'if' above so that unparseable strings 1715 // without raw input format to the empty string instead of "+00" 1716 /** @type {string} */ 1717 var rawInput = number.getRawInputOrDefault(); 1718 if (rawInput.length > 0) { 1719 return rawInput; 1720 } 1721 } 1722 /** @type {number} */ 1723 var countryCallingCode = number.getCountryCodeOrDefault(); 1724 /** @type {string} */ 1725 var nationalSignificantNumber = this.getNationalSignificantNumber(number); 1726 if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.E164) { 1727 // Early exit for E164 case (even if the country calling code is invalid) 1728 // since no formatting of the national number needs to be applied. 1729 // Extensions are not formatted. 1730 return this.prefixNumberWithCountryCallingCode_( 1731 countryCallingCode, i18n.phonenumbers.PhoneNumberFormat.E164, 1732 nationalSignificantNumber, ''); 1733 } 1734 if (!this.hasValidCountryCallingCode_(countryCallingCode)) { 1735 return nationalSignificantNumber; 1736 } 1737 // Note getRegionCodeForCountryCode() is used because formatting information 1738 // for regions which share a country calling code is contained by only one 1739 // region for performance reasons. For example, for NANPA regions it will be 1740 // contained in the metadata for US. 1741 /** @type {string} */ 1742 var regionCode = this.getRegionCodeForCountryCode(countryCallingCode); 1743 1744 // Metadata cannot be null because the country calling code is valid (which 1745 // means that the region code cannot be ZZ and must be one of our supported 1746 // region codes). 1747 /** @type {i18n.phonenumbers.PhoneMetadata} */ 1748 var metadata = 1749 this.getMetadataForRegionOrCallingCode_(countryCallingCode, regionCode); 1750 /** @type {string} */ 1751 var formattedExtension = 1752 this.maybeGetFormattedExtension_(number, metadata, numberFormat); 1753 /** @type {string} */ 1754 var formattedNationalNumber = 1755 this.formatNsn_(nationalSignificantNumber, metadata, numberFormat); 1756 return this.prefixNumberWithCountryCallingCode_(countryCallingCode, 1757 numberFormat, 1758 formattedNationalNumber, 1759 formattedExtension); 1760}; 1761 1762 1763/** 1764 * Formats a phone number in the specified format using client-defined 1765 * formatting rules. Note that if the phone number has a country calling code of 1766 * zero or an otherwise invalid country calling code, we cannot work out things 1767 * like whether there should be a national prefix applied, or how to format 1768 * extensions, so we return the national significant number with no formatting 1769 * applied. 1770 * 1771 * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be 1772 * formatted. 1773 * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the 1774 * phone number should be formatted into. 1775 * @param {Array.<i18n.phonenumbers.NumberFormat>} userDefinedFormats formatting 1776 * rules specified by clients. 1777 * @return {string} the formatted phone number. 1778 */ 1779i18n.phonenumbers.PhoneNumberUtil.prototype.formatByPattern = 1780 function(number, numberFormat, userDefinedFormats) { 1781 1782 /** @type {number} */ 1783 var countryCallingCode = number.getCountryCodeOrDefault(); 1784 /** @type {string} */ 1785 var nationalSignificantNumber = this.getNationalSignificantNumber(number); 1786 if (!this.hasValidCountryCallingCode_(countryCallingCode)) { 1787 return nationalSignificantNumber; 1788 } 1789 // Note getRegionCodeForCountryCode() is used because formatting information 1790 // for regions which share a country calling code is contained by only one 1791 // region for performance reasons. For example, for NANPA regions it will be 1792 // contained in the metadata for US. 1793 /** @type {string} */ 1794 var regionCode = this.getRegionCodeForCountryCode(countryCallingCode); 1795 // Metadata cannot be null because the country calling code is valid 1796 /** @type {i18n.phonenumbers.PhoneMetadata} */ 1797 var metadata = 1798 this.getMetadataForRegionOrCallingCode_(countryCallingCode, regionCode); 1799 1800 /** @type {string} */ 1801 var formattedNumber = ''; 1802 1803 /** @type {i18n.phonenumbers.NumberFormat} */ 1804 var formattingPattern = this.chooseFormattingPatternForNumber_( 1805 userDefinedFormats, nationalSignificantNumber); 1806 if (formattingPattern == null) { 1807 // If no pattern above is matched, we format the number as a whole. 1808 formattedNumber = nationalSignificantNumber; 1809 } else { 1810 // Before we do a replacement of the national prefix pattern $NP with the 1811 // national prefix, we need to copy the rule so that subsequent replacements 1812 // for different numbers have the appropriate national prefix. 1813 /** @type {i18n.phonenumbers.NumberFormat} */ 1814 var numFormatCopy = formattingPattern.clone(); 1815 /** @type {string} */ 1816 var nationalPrefixFormattingRule = 1817 formattingPattern.getNationalPrefixFormattingRuleOrDefault(); 1818 if (nationalPrefixFormattingRule.length > 0) { 1819 /** @type {string} */ 1820 var nationalPrefix = metadata.getNationalPrefixOrDefault(); 1821 if (nationalPrefix.length > 0) { 1822 // Replace $NP with national prefix and $FG with the first group ($1). 1823 nationalPrefixFormattingRule = nationalPrefixFormattingRule 1824 .replace(i18n.phonenumbers.PhoneNumberUtil.NP_PATTERN_, 1825 nationalPrefix) 1826 .replace(i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_, '$1'); 1827 numFormatCopy.setNationalPrefixFormattingRule( 1828 nationalPrefixFormattingRule); 1829 } else { 1830 // We don't want to have a rule for how to format the national prefix if 1831 // there isn't one. 1832 numFormatCopy.clearNationalPrefixFormattingRule(); 1833 } 1834 } 1835 formattedNumber = this.formatNsnUsingPattern_( 1836 nationalSignificantNumber, numFormatCopy, numberFormat); 1837 } 1838 1839 /** @type {string} */ 1840 var formattedExtension = 1841 this.maybeGetFormattedExtension_(number, metadata, numberFormat); 1842 return this.prefixNumberWithCountryCallingCode_(countryCallingCode, 1843 numberFormat, 1844 formattedNumber, 1845 formattedExtension); 1846}; 1847 1848 1849/** 1850 * Formats a phone number in national format for dialing using the carrier as 1851 * specified in the {@code carrierCode}. The {@code carrierCode} will always be 1852 * used regardless of whether the phone number already has a preferred domestic 1853 * carrier code stored. If {@code carrierCode} contains an empty string, returns 1854 * the number in national format without any carrier code. 1855 * 1856 * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be 1857 * formatted. 1858 * @param {string} carrierCode the carrier selection code to be used. 1859 * @return {string} the formatted phone number in national format for dialing 1860 * using the carrier as specified in the {@code carrierCode}. 1861 */ 1862i18n.phonenumbers.PhoneNumberUtil.prototype. 1863 formatNationalNumberWithCarrierCode = function(number, carrierCode) { 1864 1865 /** @type {number} */ 1866 var countryCallingCode = number.getCountryCodeOrDefault(); 1867 /** @type {string} */ 1868 var nationalSignificantNumber = this.getNationalSignificantNumber(number); 1869 if (!this.hasValidCountryCallingCode_(countryCallingCode)) { 1870 return nationalSignificantNumber; 1871 } 1872 1873 // Note getRegionCodeForCountryCode() is used because formatting information 1874 // for regions which share a country calling code is contained by only one 1875 // region for performance reasons. For example, for NANPA regions it will be 1876 // contained in the metadata for US. 1877 /** @type {string} */ 1878 var regionCode = this.getRegionCodeForCountryCode(countryCallingCode); 1879 // Metadata cannot be null because the country calling code is valid. 1880 /** @type {i18n.phonenumbers.PhoneMetadata} */ 1881 var metadata = 1882 this.getMetadataForRegionOrCallingCode_(countryCallingCode, regionCode); 1883 /** @type {string} */ 1884 var formattedExtension = this.maybeGetFormattedExtension_( 1885 number, metadata, i18n.phonenumbers.PhoneNumberFormat.NATIONAL); 1886 /** @type {string} */ 1887 var formattedNationalNumber = this.formatNsn_( 1888 nationalSignificantNumber, metadata, 1889 i18n.phonenumbers.PhoneNumberFormat.NATIONAL, carrierCode); 1890 return this.prefixNumberWithCountryCallingCode_( 1891 countryCallingCode, i18n.phonenumbers.PhoneNumberFormat.NATIONAL, 1892 formattedNationalNumber, formattedExtension); 1893}; 1894 1895 1896/** 1897 * @param {number} countryCallingCode 1898 * @param {?string} regionCode 1899 * @return {i18n.phonenumbers.PhoneMetadata} 1900 * @private 1901 */ 1902i18n.phonenumbers.PhoneNumberUtil.prototype.getMetadataForRegionOrCallingCode_ = 1903 function(countryCallingCode, regionCode) { 1904 return i18n.phonenumbers.PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY == 1905 regionCode ? 1906 this.getMetadataForNonGeographicalRegion(countryCallingCode) : 1907 this.getMetadataForRegion(regionCode); 1908}; 1909 1910 1911/** 1912 * Formats a phone number in national format for dialing using the carrier as 1913 * specified in the preferred_domestic_carrier_code field of the PhoneNumber 1914 * object passed in. If that is missing, use the {@code fallbackCarrierCode} 1915 * passed in instead. If there is no {@code preferred_domestic_carrier_code}, 1916 * and the {@code fallbackCarrierCode} contains an empty string, return the 1917 * number in national format without any carrier code. 1918 * 1919 * <p>Use {@link #formatNationalNumberWithCarrierCode} instead if the carrier 1920 * code passed in should take precedence over the number's 1921 * {@code preferred_domestic_carrier_code} when formatting. 1922 * 1923 * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be 1924 * formatted. 1925 * @param {string} fallbackCarrierCode the carrier selection code to be used, if 1926 * none is found in the phone number itself. 1927 * @return {string} the formatted phone number in national format for dialing 1928 * using the number's preferred_domestic_carrier_code, or the 1929 * {@code fallbackCarrierCode} passed in if none is found. 1930 */ 1931i18n.phonenumbers.PhoneNumberUtil.prototype. 1932 formatNationalNumberWithPreferredCarrierCode = function( 1933 number, fallbackCarrierCode) { 1934 return this.formatNationalNumberWithCarrierCode( 1935 number, 1936 // Historically, we set this to an empty string when parsing with raw 1937 // input if none was found in the input string. However, this doesn't 1938 // result in a number we can dial. For this reason, we treat the empty 1939 // string the same as if it isn't set at all. 1940 number.getPreferredDomesticCarrierCodeOrDefault().length > 0 ? 1941 number.getPreferredDomesticCarrierCodeOrDefault() : 1942 fallbackCarrierCode); 1943}; 1944 1945 1946/** 1947 * Returns a number formatted in such a way that it can be dialed from a mobile 1948 * phone in a specific region. If the number cannot be reached from the region 1949 * (e.g. some countries block toll-free numbers from being called outside of the 1950 * country), the method returns an empty string. 1951 * 1952 * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be 1953 * formatted. 1954 * @param {string} regionCallingFrom the region where the call is being placed. 1955 * @param {boolean} withFormatting whether the number should be returned with 1956 * formatting symbols, such as spaces and dashes. 1957 * @return {string} the formatted phone number. 1958 */ 1959i18n.phonenumbers.PhoneNumberUtil.prototype.formatNumberForMobileDialing = 1960 function(number, regionCallingFrom, withFormatting) { 1961 1962 /** @type {number} */ 1963 var countryCallingCode = number.getCountryCodeOrDefault(); 1964 if (!this.hasValidCountryCallingCode_(countryCallingCode)) { 1965 return number.hasRawInput() ? number.getRawInputOrDefault() : ''; 1966 } 1967 1968 /** @type {string} */ 1969 var formattedNumber = ''; 1970 // Clear the extension, as that part cannot normally be dialed together with 1971 // the main number. 1972 /** @type {i18n.phonenumbers.PhoneNumber} */ 1973 var numberNoExt = number.clone(); 1974 numberNoExt.clearExtension(); 1975 /** @type {string} */ 1976 var regionCode = this.getRegionCodeForCountryCode(countryCallingCode); 1977 /** @type {i18n.phonenumbers.PhoneNumberType} */ 1978 var numberType = this.getNumberType(numberNoExt); 1979 /** @type {boolean} */ 1980 var isValidNumber = (numberType != i18n.phonenumbers.PhoneNumberType.UNKNOWN); 1981 if (regionCallingFrom == regionCode) { 1982 /** @type {boolean} */ 1983 var isFixedLineOrMobile = 1984 (numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE) || 1985 (numberType == i18n.phonenumbers.PhoneNumberType.MOBILE) || 1986 (numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE); 1987 // Carrier codes may be needed in some countries. We handle this here. 1988 if (regionCode == 'CO' && 1989 numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE) { 1990 formattedNumber = this.formatNationalNumberWithCarrierCode( 1991 numberNoExt, 1992 i18n.phonenumbers.PhoneNumberUtil 1993 .COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX_); 1994 } else if (regionCode == 'BR' && isFixedLineOrMobile) { 1995 formattedNumber = 1996 // Historically, we set this to an empty string when parsing with raw 1997 // input if none was found in the input string. However, this doesn't 1998 // result in a number we can dial. For this reason, we treat the empty 1999 // string the same as if it isn't set at all. 2000 numberNoExt.getPreferredDomesticCarrierCodeOrDefault().length > 0 ? 2001 this.formatNationalNumberWithPreferredCarrierCode(numberNoExt, '') : 2002 // Brazilian fixed line and mobile numbers need to be dialed with a 2003 // carrier code when called within Brazil. Without that, most of the 2004 // carriers won't connect the call. Because of that, we return an 2005 // empty string here. 2006 ''; 2007 } else if (countryCallingCode == 2008 i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_) { 2009 // For NANPA countries, we output international format for numbers that 2010 // can be dialed internationally, since that always works, except for 2011 // numbers which might potentially be short numbers, which are always 2012 // dialled in national format. 2013 /** @type {i18n.phonenumbers.PhoneMetadata} */ 2014 var regionMetadata = this.getMetadataForRegion(regionCallingFrom); 2015 if (this.canBeInternationallyDialled(numberNoExt) && 2016 this.testNumberLength_(this.getNationalSignificantNumber(numberNoExt), 2017 regionMetadata) != 2018 i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT) { 2019 formattedNumber = this.format( 2020 numberNoExt, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL); 2021 } else { 2022 formattedNumber = this.format( 2023 numberNoExt, i18n.phonenumbers.PhoneNumberFormat.NATIONAL); 2024 } 2025 } else { 2026 // For non-geographical countries, and Mexican, Chilean and Uzbek fixed 2027 // line and mobile numbers, we output international format for numbers 2028 // that can be dialed internationally as that always works. 2029 if ((regionCode == 2030 i18n.phonenumbers.PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY || 2031 // MX fixed line and mobile numbers should always be formatted in 2032 // international format, even when dialed within MX. For national 2033 // format to work, a carrier code needs to be used, and the correct 2034 // carrier code depends on if the caller and callee are from the 2035 // same local area. It is trickier to get that to work correctly than 2036 // using international format, which is tested to work fine on all 2037 // carriers. 2038 // CL fixed line numbers need the national prefix when dialing in the 2039 // national format, but don't have it when used for display. The 2040 // reverse is true for mobile numbers. As a result, we output them in 2041 // the international format to make it work. 2042 // UZ mobile and fixed-line numbers have to be formatted in 2043 // international format or prefixed with special codes like 03, 04 2044 // (for fixed-line) and 05 (for mobile) for dialling successfully 2045 // from mobile devices. As we do not have complete information on 2046 // special codes and to be consistent with formatting across all 2047 // phone types we return the number in international format here. 2048 ((regionCode == 'MX' || regionCode == 'CL' || regionCode == 'UZ') && 2049 isFixedLineOrMobile)) && 2050 this.canBeInternationallyDialled(numberNoExt)) { 2051 formattedNumber = this.format( 2052 numberNoExt, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL); 2053 } else { 2054 formattedNumber = this.format( 2055 numberNoExt, i18n.phonenumbers.PhoneNumberFormat.NATIONAL); 2056 } 2057 } 2058 } else if (isValidNumber && this.canBeInternationallyDialled(numberNoExt)) { 2059 // We assume that short numbers are not diallable from outside their region, 2060 // so if a number is not a valid regular length phone number, we treat it as 2061 // if it cannot be internationally dialled. 2062 return withFormatting ? 2063 this.format(numberNoExt, 2064 i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL) : 2065 this.format(numberNoExt, i18n.phonenumbers.PhoneNumberFormat.E164); 2066 } 2067 return withFormatting ? 2068 formattedNumber : 2069 i18n.phonenumbers.PhoneNumberUtil.normalizeDiallableCharsOnly( 2070 formattedNumber); 2071}; 2072 2073 2074/** 2075 * Formats a phone number for out-of-country dialing purposes. If no 2076 * regionCallingFrom is supplied, we format the number in its INTERNATIONAL 2077 * format. If the country calling code is the same as that of the region where 2078 * the number is from, then NATIONAL formatting will be applied. 2079 * 2080 * <p>If the number itself has a country calling code of zero or an otherwise 2081 * invalid country calling code, then we return the number with no formatting 2082 * applied. 2083 * 2084 * <p>Note this function takes care of the case for calling inside of NANPA and 2085 * between Russia and Kazakhstan (who share the same country calling code). In 2086 * those cases, no international prefix is used. For regions which have multiple 2087 * international prefixes, the number in its INTERNATIONAL format will be 2088 * returned instead. 2089 * 2090 * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be 2091 * formatted. 2092 * @param {string} regionCallingFrom the region where the call is being placed. 2093 * @return {string} the formatted phone number. 2094 */ 2095i18n.phonenumbers.PhoneNumberUtil.prototype.formatOutOfCountryCallingNumber = 2096 function(number, regionCallingFrom) { 2097 2098 if (!this.isValidRegionCode_(regionCallingFrom)) { 2099 return this.format(number, 2100 i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL); 2101 } 2102 /** @type {number} */ 2103 var countryCallingCode = number.getCountryCodeOrDefault(); 2104 /** @type {string} */ 2105 var nationalSignificantNumber = this.getNationalSignificantNumber(number); 2106 if (!this.hasValidCountryCallingCode_(countryCallingCode)) { 2107 return nationalSignificantNumber; 2108 } 2109 if (countryCallingCode == 2110 i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_) { 2111 if (this.isNANPACountry(regionCallingFrom)) { 2112 // For NANPA regions, return the national format for these regions but 2113 // prefix it with the country calling code. 2114 return countryCallingCode + ' ' + 2115 this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL); 2116 } 2117 } else if (countryCallingCode == 2118 this.getCountryCodeForValidRegion_(regionCallingFrom)) { 2119 // If regions share a country calling code, the country calling code need 2120 // not be dialled. This also applies when dialling within a region, so this 2121 // if clause covers both these cases. Technically this is the case for 2122 // dialling from La Reunion to other overseas departments of France (French 2123 // Guiana, Martinique, Guadeloupe), but not vice versa - so we don't cover 2124 // this edge case for now and for those cases return the version including 2125 // country calling code. Details here: 2126 // http://www.petitfute.com/voyage/225-info-pratiques-reunion 2127 return this.format(number, 2128 i18n.phonenumbers.PhoneNumberFormat.NATIONAL); 2129 } 2130 // Metadata cannot be null because we checked 'isValidRegionCode()' above. 2131 /** @type {i18n.phonenumbers.PhoneMetadata} */ 2132 var metadataForRegionCallingFrom = 2133 this.getMetadataForRegion(regionCallingFrom); 2134 /** @type {string} */ 2135 var internationalPrefix = 2136 metadataForRegionCallingFrom.getInternationalPrefixOrDefault(); 2137 2138 // For regions that have multiple international prefixes, the international 2139 // format of the number is returned, unless there is a preferred international 2140 // prefix. 2141 /** @type {string} */ 2142 var internationalPrefixForFormatting = ''; 2143 if (metadataForRegionCallingFrom.hasPreferredInternationalPrefix()) { 2144 internationalPrefixForFormatting = 2145 metadataForRegionCallingFrom.getPreferredInternationalPrefixOrDefault(); 2146 } else if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely( 2147 i18n.phonenumbers.PhoneNumberUtil.SINGLE_INTERNATIONAL_PREFIX_, 2148 internationalPrefix)) { 2149 internationalPrefixForFormatting = internationalPrefix; 2150 } 2151 2152 /** @type {string} */ 2153 var regionCode = this.getRegionCodeForCountryCode(countryCallingCode); 2154 // Metadata cannot be null because the country calling code is valid. 2155 /** @type {i18n.phonenumbers.PhoneMetadata} */ 2156 var metadataForRegion = 2157 this.getMetadataForRegionOrCallingCode_(countryCallingCode, regionCode); 2158 /** @type {string} */ 2159 var formattedNationalNumber = this.formatNsn_( 2160 nationalSignificantNumber, metadataForRegion, 2161 i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL); 2162 /** @type {string} */ 2163 var formattedExtension = this.maybeGetFormattedExtension_(number, 2164 metadataForRegion, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL); 2165 return internationalPrefixForFormatting.length > 0 ? 2166 internationalPrefixForFormatting + ' ' + countryCallingCode + ' ' + 2167 formattedNationalNumber + formattedExtension : 2168 this.prefixNumberWithCountryCallingCode_( 2169 countryCallingCode, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL, 2170 formattedNationalNumber, formattedExtension); 2171}; 2172 2173 2174/** 2175 * Formats a phone number using the original phone number format that the number 2176 * is parsed from. The original format is embedded in the country_code_source 2177 * field of the PhoneNumber object passed in. If such information is missing, 2178 * the number will be formatted into the NATIONAL format by default. When the 2179 * number contains a leading zero and this is unexpected for this country, or 2180 * we don't have a formatting pattern for the number, the method returns the 2181 * raw input when it is available. 2182 * 2183 * Note this method guarantees no digit will be inserted, removed or modified as 2184 * a result of formatting. 2185 * 2186 * @param {i18n.phonenumbers.PhoneNumber} number the phone number that needs to 2187 * be formatted in its original number format. 2188 * @param {string} regionCallingFrom the region whose IDD needs to be prefixed 2189 * if the original number has one. 2190 * @return {string} the formatted phone number in its original number format. 2191 */ 2192i18n.phonenumbers.PhoneNumberUtil.prototype.formatInOriginalFormat = 2193 function(number, regionCallingFrom) { 2194 2195 if (number.hasRawInput() && !this.hasFormattingPatternForNumber_(number)) { 2196 // We check if we have the formatting pattern because without that, we might 2197 // format the number as a group without national prefix. 2198 return number.getRawInputOrDefault(); 2199 } 2200 if (!number.hasCountryCodeSource()) { 2201 return this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL); 2202 } 2203 /** @type {string} */ 2204 var formattedNumber; 2205 switch (number.getCountryCodeSource()) { 2206 case i18n.phonenumbers.PhoneNumber.CountryCodeSource 2207 .FROM_NUMBER_WITH_PLUS_SIGN: 2208 formattedNumber = this.format(number, 2209 i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL); 2210 break; 2211 case i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD: 2212 formattedNumber = 2213 this.formatOutOfCountryCallingNumber(number, regionCallingFrom); 2214 break; 2215 case i18n.phonenumbers.PhoneNumber.CountryCodeSource 2216 .FROM_NUMBER_WITHOUT_PLUS_SIGN: 2217 formattedNumber = this.format(number, 2218 i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL).substring(1); 2219 break; 2220 case i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY: 2221 // Fall-through to default case. 2222 default: 2223 /** @type {string} */ 2224 var regionCode = 2225 this.getRegionCodeForCountryCode(number.getCountryCodeOrDefault()); 2226 // We strip non-digits from the NDD here, and from the raw input later, 2227 // so that we can compare them easily. 2228 /** @type {?string} */ 2229 var nationalPrefix = this.getNddPrefixForRegion(regionCode, true); 2230 /** @type {string} */ 2231 var nationalFormat = 2232 this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL); 2233 if (nationalPrefix == null || nationalPrefix.length == 0) { 2234 // If the region doesn't have a national prefix at all, we can safely 2235 // return the national format without worrying about a national prefix 2236 // being added. 2237 formattedNumber = nationalFormat; 2238 break; 2239 } 2240 // Otherwise, we check if the original number was entered with a national 2241 // prefix. 2242 if (this.rawInputContainsNationalPrefix_( 2243 number.getRawInputOrDefault(), nationalPrefix, regionCode)) { 2244 // If so, we can safely return the national format. 2245 formattedNumber = nationalFormat; 2246 break; 2247 } 2248 // Metadata cannot be null here because getNddPrefixForRegion() (above) 2249 // returns null if there is no metadata for the region. 2250 /** @type {i18n.phonenumbers.PhoneMetadata} */ 2251 var metadata = this.getMetadataForRegion(regionCode); 2252 /** @type {string} */ 2253 var nationalNumber = this.getNationalSignificantNumber(number); 2254 /** @type {i18n.phonenumbers.NumberFormat} */ 2255 var formatRule = this.chooseFormattingPatternForNumber_( 2256 metadata.numberFormatArray(), nationalNumber); 2257 // The format rule could still be null here if the national number was 0 2258 // and there was no raw input (this should not be possible for numbers 2259 // generated by the phonenumber library as they would also not have a 2260 // country calling code and we would have exited earlier). 2261 if (formatRule == null) { 2262 formattedNumber = nationalFormat; 2263 break; 2264 } 2265 // When the format we apply to this number doesn't contain national 2266 // prefix, we can just return the national format. 2267 // TODO: Refactor the code below with the code in 2268 // isNationalPrefixPresentIfRequired. 2269 /** @type {string} */ 2270 var candidateNationalPrefixRule = 2271 formatRule.getNationalPrefixFormattingRuleOrDefault(); 2272 // We assume that the first-group symbol will never be _before_ the 2273 // national prefix. 2274 /** @type {number} */ 2275 var indexOfFirstGroup = candidateNationalPrefixRule.indexOf('$1'); 2276 if (indexOfFirstGroup <= 0) { 2277 formattedNumber = nationalFormat; 2278 break; 2279 } 2280 candidateNationalPrefixRule = 2281 candidateNationalPrefixRule.substring(0, indexOfFirstGroup); 2282 candidateNationalPrefixRule = i18n.phonenumbers.PhoneNumberUtil 2283 .normalizeDigitsOnly(candidateNationalPrefixRule); 2284 if (candidateNationalPrefixRule.length == 0) { 2285 // National prefix not used when formatting this number. 2286 formattedNumber = nationalFormat; 2287 break; 2288 } 2289 // Otherwise, we need to remove the national prefix from our output. 2290 /** @type {i18n.phonenumbers.NumberFormat} */ 2291 var numFormatCopy = formatRule.clone(); 2292 numFormatCopy.clearNationalPrefixFormattingRule(); 2293 formattedNumber = this.formatByPattern(number, 2294 i18n.phonenumbers.PhoneNumberFormat.NATIONAL, [numFormatCopy]); 2295 break; 2296 } 2297 /** @type {string} */ 2298 var rawInput = number.getRawInputOrDefault(); 2299 // If no digit is inserted/removed/modified as a result of our formatting, we 2300 // return the formatted phone number; otherwise we return the raw input the 2301 // user entered. 2302 if (formattedNumber != null && rawInput.length > 0) { 2303 /** @type {string} */ 2304 var normalizedFormattedNumber = 2305 i18n.phonenumbers.PhoneNumberUtil.normalizeDiallableCharsOnly( 2306 formattedNumber); 2307 /** @type {string} */ 2308 var normalizedRawInput = 2309 i18n.phonenumbers.PhoneNumberUtil.normalizeDiallableCharsOnly(rawInput); 2310 if (normalizedFormattedNumber != normalizedRawInput) { 2311 formattedNumber = rawInput; 2312 } 2313 } 2314 return formattedNumber; 2315}; 2316 2317 2318/** 2319 * Check if rawInput, which is assumed to be in the national format, has a 2320 * national prefix. The national prefix is assumed to be in digits-only form. 2321 * @param {string} rawInput 2322 * @param {string} nationalPrefix 2323 * @param {string} regionCode 2324 * @return {boolean} 2325 * @private 2326 */ 2327i18n.phonenumbers.PhoneNumberUtil.prototype.rawInputContainsNationalPrefix_ = 2328 function(rawInput, nationalPrefix, regionCode) { 2329 2330 /** @type {string} */ 2331 var normalizedNationalNumber = 2332 i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly(rawInput); 2333 if (goog.string.startsWith(normalizedNationalNumber, nationalPrefix)) { 2334 try { 2335 // Some Japanese numbers (e.g. 00777123) might be mistaken to contain the 2336 // national prefix when written without it (e.g. 0777123) if we just do 2337 // prefix matching. To tackle that, we check the validity of the number if 2338 // the assumed national prefix is removed (777123 won't be valid in 2339 // Japan). 2340 return this.isValidNumber( 2341 this.parse(normalizedNationalNumber.substring(nationalPrefix.length), 2342 regionCode)); 2343 } catch (e) { 2344 return false; 2345 } 2346 } 2347 return false; 2348}; 2349 2350 2351/** 2352 * @param {i18n.phonenumbers.PhoneNumber} number 2353 * @return {boolean} 2354 * @private 2355 */ 2356i18n.phonenumbers.PhoneNumberUtil.prototype.hasFormattingPatternForNumber_ = 2357 function(number) { 2358 2359 /** @type {number} */ 2360 var countryCallingCode = number.getCountryCodeOrDefault(); 2361 /** @type {string} */ 2362 var phoneNumberRegion = this.getRegionCodeForCountryCode(countryCallingCode); 2363 /** @type {i18n.phonenumbers.PhoneMetadata} */ 2364 var metadata = this.getMetadataForRegionOrCallingCode_( 2365 countryCallingCode, phoneNumberRegion); 2366 if (metadata == null) { 2367 return false; 2368 } 2369 /** @type {string} */ 2370 var nationalNumber = this.getNationalSignificantNumber(number); 2371 /** @type {i18n.phonenumbers.NumberFormat} */ 2372 var formatRule = this.chooseFormattingPatternForNumber_( 2373 metadata.numberFormatArray(), nationalNumber); 2374 return formatRule != null; 2375}; 2376 2377 2378/** 2379 * Formats a phone number for out-of-country dialing purposes. 2380 * 2381 * Note that in this version, if the number was entered originally using alpha 2382 * characters and this version of the number is stored in raw_input, this 2383 * representation of the number will be used rather than the digit 2384 * representation. Grouping information, as specified by characters such as '-' 2385 * and ' ', will be retained. 2386 * 2387 * <p><b>Caveats:</b></p> 2388 * <ul> 2389 * <li>This will not produce good results if the country calling code is both 2390 * present in the raw input _and_ is the start of the national number. This is 2391 * not a problem in the regions which typically use alpha numbers. 2392 * <li>This will also not produce good results if the raw input has any grouping 2393 * information within the first three digits of the national number, and if the 2394 * function needs to strip preceding digits/words in the raw input before these 2395 * digits. Normally people group the first three digits together so this is not 2396 * a huge problem - and will be fixed if it proves to be so. 2397 * </ul> 2398 * 2399 * @param {i18n.phonenumbers.PhoneNumber} number the phone number that needs to 2400 * be formatted. 2401 * @param {string} regionCallingFrom the region where the call is being placed. 2402 * @return {string} the formatted phone number. 2403 */ 2404i18n.phonenumbers.PhoneNumberUtil.prototype. 2405 formatOutOfCountryKeepingAlphaChars = function(number, regionCallingFrom) { 2406 /** @type {string} */ 2407 var rawInput = number.getRawInputOrDefault(); 2408 // If there is no raw input, then we can't keep alpha characters because there 2409 // aren't any. In this case, we return formatOutOfCountryCallingNumber. 2410 if (rawInput.length == 0) { 2411 return this.formatOutOfCountryCallingNumber(number, regionCallingFrom); 2412 } 2413 /** @type {number} */ 2414 var countryCode = number.getCountryCodeOrDefault(); 2415 if (!this.hasValidCountryCallingCode_(countryCode)) { 2416 return rawInput; 2417 } 2418 // Strip any prefix such as country calling code, IDD, that was present. We do 2419 // this by comparing the number in raw_input with the parsed number. To do 2420 // this, first we normalize punctuation. We retain number grouping symbols 2421 // such as ' ' only. 2422 rawInput = i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_( 2423 rawInput, 2424 i18n.phonenumbers.PhoneNumberUtil.ALL_PLUS_NUMBER_GROUPING_SYMBOLS_, 2425 true); 2426 // Now we trim everything before the first three digits in the parsed number. 2427 // We choose three because all valid alpha numbers have 3 digits at the start 2428 // - if it does not, then we don't trim anything at all. Similarly, if the 2429 // national number was less than three digits, we don't trim anything at all. 2430 /** @type {string} */ 2431 var nationalNumber = this.getNationalSignificantNumber(number); 2432 if (nationalNumber.length > 3) { 2433 /** @type {number} */ 2434 var firstNationalNumberDigit = 2435 rawInput.indexOf(nationalNumber.substring(0, 3)); 2436 if (firstNationalNumberDigit != -1) { 2437 rawInput = rawInput.substring(firstNationalNumberDigit); 2438 } 2439 } 2440 /** @type {i18n.phonenumbers.PhoneMetadata} */ 2441 var metadataForRegionCallingFrom = 2442 this.getMetadataForRegion(regionCallingFrom); 2443 if (countryCode == i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_) { 2444 if (this.isNANPACountry(regionCallingFrom)) { 2445 return countryCode + ' ' + rawInput; 2446 } 2447 } else if (metadataForRegionCallingFrom != null && 2448 countryCode == this.getCountryCodeForValidRegion_(regionCallingFrom)) { 2449 /** @type {i18n.phonenumbers.NumberFormat} */ 2450 var formattingPattern = this.chooseFormattingPatternForNumber_( 2451 metadataForRegionCallingFrom.numberFormatArray(), nationalNumber); 2452 if (formattingPattern == null) { 2453 // If no pattern above is matched, we format the original input. 2454 return rawInput; 2455 } 2456 /** @type {i18n.phonenumbers.NumberFormat} */ 2457 var newFormat = formattingPattern.clone(); 2458 // The first group is the first group of digits that the user wrote 2459 // together. 2460 newFormat.setPattern('(\\d+)(.*)'); 2461 // Here we just concatenate them back together after the national prefix 2462 // has been fixed. 2463 newFormat.setFormat('$1$2'); 2464 // Now we format using this pattern instead of the default pattern, but 2465 // with the national prefix prefixed if necessary. 2466 // This will not work in the cases where the pattern (and not the leading 2467 // digits) decide whether a national prefix needs to be used, since we have 2468 // overridden the pattern to match anything, but that is not the case in the 2469 // metadata to date. 2470 return this.formatNsnUsingPattern_(rawInput, newFormat, 2471 i18n.phonenumbers.PhoneNumberFormat.NATIONAL); 2472 } 2473 /** @type {string} */ 2474 var internationalPrefixForFormatting = ''; 2475 // If an unsupported region-calling-from is entered, or a country with 2476 // multiple international prefixes, the international format of the number is 2477 // returned, unless there is a preferred international prefix. 2478 if (metadataForRegionCallingFrom != null) { 2479 /** @type {string} */ 2480 var internationalPrefix = 2481 metadataForRegionCallingFrom.getInternationalPrefixOrDefault(); 2482 internationalPrefixForFormatting = 2483 i18n.phonenumbers.PhoneNumberUtil.matchesEntirely( 2484 i18n.phonenumbers.PhoneNumberUtil.SINGLE_INTERNATIONAL_PREFIX_, 2485 internationalPrefix) ? 2486 internationalPrefix : 2487 metadataForRegionCallingFrom.getPreferredInternationalPrefixOrDefault(); 2488 } 2489 /** @type {string} */ 2490 var regionCode = this.getRegionCodeForCountryCode(countryCode); 2491 // Metadata cannot be null because the country calling code is valid. 2492 /** @type {i18n.phonenumbers.PhoneMetadata} */ 2493 var metadataForRegion = 2494 this.getMetadataForRegionOrCallingCode_(countryCode, regionCode); 2495 /** @type {string} */ 2496 var formattedExtension = this.maybeGetFormattedExtension_( 2497 number, metadataForRegion, 2498 i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL); 2499 if (internationalPrefixForFormatting.length > 0) { 2500 return internationalPrefixForFormatting + ' ' + countryCode + ' ' + 2501 rawInput + formattedExtension; 2502 } else { 2503 // Invalid region entered as country-calling-from (so no metadata was found 2504 // for it) or the region chosen has multiple international dialling 2505 // prefixes. 2506 return this.prefixNumberWithCountryCallingCode_( 2507 countryCode, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL, 2508 rawInput, formattedExtension); 2509 } 2510}; 2511 2512 2513/** 2514 * Gets the national significant number of a phone number. Note a national 2515 * significant number doesn't contain a national prefix or any formatting. 2516 * 2517 * @param {i18n.phonenumbers.PhoneNumber} number the phone number for which the 2518 * national significant number is needed. 2519 * @return {string} the national significant number of the PhoneNumber object 2520 * passed in. 2521 */ 2522i18n.phonenumbers.PhoneNumberUtil.prototype.getNationalSignificantNumber = 2523 function(number) { 2524 2525 if (!number.hasNationalNumber()) { 2526 return ''; 2527 } 2528 /** @type {string} */ 2529 var nationalNumber = '' + number.getNationalNumber(); 2530 // If leading zero(s) have been set, we prefix this now. Note that a single 2531 // leading zero is not the same as a national prefix; leading zeros should be 2532 // dialled no matter whether you are dialling from within or outside the 2533 // country, national prefixes are added when formatting nationally if 2534 // applicable. 2535 if (number.hasItalianLeadingZero() && number.getItalianLeadingZero() && 2536 number.getNumberOfLeadingZerosOrDefault() > 0) { 2537 return Array(number.getNumberOfLeadingZerosOrDefault() + 1).join('0') + 2538 nationalNumber; 2539 } 2540 return nationalNumber; 2541}; 2542 2543 2544/** 2545 * A helper function that is used by format and formatByPattern. 2546 * 2547 * @param {number} countryCallingCode the country calling code. 2548 * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the 2549 * phone number should be formatted into. 2550 * @param {string} formattedNationalNumber 2551 * @param {string} formattedExtension 2552 * @return {string} the formatted phone number. 2553 * @private 2554 */ 2555i18n.phonenumbers.PhoneNumberUtil.prototype. 2556 prefixNumberWithCountryCallingCode_ = function(countryCallingCode, 2557 numberFormat, 2558 formattedNationalNumber, 2559 formattedExtension) { 2560 2561 switch (numberFormat) { 2562 case i18n.phonenumbers.PhoneNumberFormat.E164: 2563 return i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCallingCode + 2564 formattedNationalNumber + formattedExtension; 2565 case i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL: 2566 return i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCallingCode + 2567 ' ' + formattedNationalNumber + formattedExtension; 2568 case i18n.phonenumbers.PhoneNumberFormat.RFC3966: 2569 return i18n.phonenumbers.PhoneNumberUtil.RFC3966_PREFIX_ + 2570 i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCallingCode + 2571 '-' + formattedNationalNumber + formattedExtension; 2572 case i18n.phonenumbers.PhoneNumberFormat.NATIONAL: 2573 default: 2574 return formattedNationalNumber + formattedExtension; 2575 } 2576}; 2577 2578 2579/** 2580 * Note in some regions, the national number can be written in two completely 2581 * different ways depending on whether it forms part of the NATIONAL format or 2582 * INTERNATIONAL format. The numberFormat parameter here is used to specify 2583 * which format to use for those cases. If a carrierCode is specified, this will 2584 * be inserted into the formatted string to replace $CC. 2585 * 2586 * @param {string} number a string of characters representing a phone number. 2587 * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the 2588 * region that we think this number is from. 2589 * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the 2590 * phone number should be formatted into. 2591 * @param {string=} opt_carrierCode 2592 * @return {string} the formatted phone number. 2593 * @private 2594 */ 2595i18n.phonenumbers.PhoneNumberUtil.prototype.formatNsn_ = 2596 function(number, metadata, numberFormat, opt_carrierCode) { 2597 2598 /** @type {Array.<i18n.phonenumbers.NumberFormat>} */ 2599 var intlNumberFormats = metadata.intlNumberFormatArray(); 2600 // When the intlNumberFormats exists, we use that to format national number 2601 // for the INTERNATIONAL format instead of using the numberDesc.numberFormats. 2602 /** @type {Array.<i18n.phonenumbers.NumberFormat>} */ 2603 var availableFormats = 2604 (intlNumberFormats.length == 0 || 2605 numberFormat == i18n.phonenumbers.PhoneNumberFormat.NATIONAL) ? 2606 metadata.numberFormatArray() : metadata.intlNumberFormatArray(); 2607 /** @type {i18n.phonenumbers.NumberFormat} */ 2608 var formattingPattern = this.chooseFormattingPatternForNumber_( 2609 availableFormats, number); 2610 return (formattingPattern == null) ? 2611 number : 2612 this.formatNsnUsingPattern_(number, formattingPattern, 2613 numberFormat, opt_carrierCode); 2614}; 2615 2616 2617/** 2618 * @param {Array.<i18n.phonenumbers.NumberFormat>} availableFormats the 2619 * available formats the phone number could be formatted into. 2620 * @param {string} nationalNumber a string of characters representing a phone 2621 * number. 2622 * @return {i18n.phonenumbers.NumberFormat} 2623 * @private 2624 */ 2625i18n.phonenumbers.PhoneNumberUtil.prototype.chooseFormattingPatternForNumber_ = 2626 function(availableFormats, nationalNumber) { 2627 2628 /** @type {i18n.phonenumbers.NumberFormat} */ 2629 var numFormat; 2630 /** @type {number} */ 2631 var l = availableFormats.length; 2632 for (var i = 0; i < l; ++i) { 2633 numFormat = availableFormats[i]; 2634 /** @type {number} */ 2635 var size = numFormat.leadingDigitsPatternCount(); 2636 if (size == 0 || 2637 // We always use the last leading_digits_pattern, as it is the most 2638 // detailed. 2639 nationalNumber 2640 .search(numFormat.getLeadingDigitsPattern(size - 1)) == 0) { 2641 /** @type {!RegExp} */ 2642 var patternToMatch = new RegExp(numFormat.getPattern()); 2643 if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely(patternToMatch, 2644 nationalNumber)) { 2645 return numFormat; 2646 } 2647 } 2648 } 2649 return null; 2650}; 2651 2652 2653/** 2654 * Note that carrierCode is optional - if null or an empty string, no carrier 2655 * code replacement will take place. 2656 * 2657 * @param {string} nationalNumber a string of characters representing a phone 2658 * number. 2659 * @param {i18n.phonenumbers.NumberFormat} formattingPattern the formatting rule 2660 * the phone number should be formatted into. 2661 * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the 2662 * phone number should be formatted into. 2663 * @param {string=} opt_carrierCode 2664 * @return {string} the formatted phone number. 2665 * @private 2666 */ 2667i18n.phonenumbers.PhoneNumberUtil.prototype.formatNsnUsingPattern_ = 2668 function(nationalNumber, formattingPattern, numberFormat, opt_carrierCode) { 2669 2670 /** @type {string} */ 2671 var numberFormatRule = formattingPattern.getFormatOrDefault(); 2672 /** @type {!RegExp} */ 2673 var patternToMatch = new RegExp(formattingPattern.getPattern()); 2674 /** @type {string} */ 2675 var domesticCarrierCodeFormattingRule = 2676 formattingPattern.getDomesticCarrierCodeFormattingRuleOrDefault(); 2677 /** @type {string} */ 2678 var formattedNationalNumber = ''; 2679 if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.NATIONAL && 2680 opt_carrierCode != null && opt_carrierCode.length > 0 && 2681 domesticCarrierCodeFormattingRule.length > 0) { 2682 // Replace the $CC in the formatting rule with the desired carrier code. 2683 /** @type {string} */ 2684 var carrierCodeFormattingRule = domesticCarrierCodeFormattingRule 2685 .replace(i18n.phonenumbers.PhoneNumberUtil.CC_PATTERN_, 2686 opt_carrierCode); 2687 // Now replace the $FG in the formatting rule with the first group and 2688 // the carrier code combined in the appropriate way. 2689 numberFormatRule = numberFormatRule.replace( 2690 i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_, 2691 carrierCodeFormattingRule); 2692 formattedNationalNumber = 2693 nationalNumber.replace(patternToMatch, numberFormatRule); 2694 } else { 2695 // Use the national prefix formatting rule instead. 2696 /** @type {string} */ 2697 var nationalPrefixFormattingRule = 2698 formattingPattern.getNationalPrefixFormattingRuleOrDefault(); 2699 if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.NATIONAL && 2700 nationalPrefixFormattingRule != null && 2701 nationalPrefixFormattingRule.length > 0) { 2702 formattedNationalNumber = nationalNumber.replace(patternToMatch, 2703 numberFormatRule.replace( 2704 i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_, 2705 nationalPrefixFormattingRule)); 2706 } else { 2707 formattedNationalNumber = 2708 nationalNumber.replace(patternToMatch, numberFormatRule); 2709 } 2710 } 2711 if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.RFC3966) { 2712 // Strip any leading punctuation. 2713 formattedNationalNumber = formattedNationalNumber.replace( 2714 new RegExp('^' + i18n.phonenumbers.PhoneNumberUtil.SEPARATOR_PATTERN_), 2715 ''); 2716 // Replace the rest with a dash between each number group. 2717 formattedNationalNumber = formattedNationalNumber.replace( 2718 new RegExp(i18n.phonenumbers.PhoneNumberUtil.SEPARATOR_PATTERN_, 'g'), 2719 '-'); 2720 } 2721 return formattedNationalNumber; 2722}; 2723 2724 2725/** 2726 * Gets a valid number for the specified region. 2727 * 2728 * @param {string} regionCode the region for which an example number is needed. 2729 * @return {i18n.phonenumbers.PhoneNumber} a valid fixed-line number for the 2730 * specified region. Returns null when the metadata does not contain such 2731 * information, or the region 001 is passed in. For 001 (representing non- 2732 * geographical numbers), call {@link #getExampleNumberForNonGeoEntity} 2733 * instead. 2734 */ 2735i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumber = 2736 function(regionCode) { 2737 2738 return this.getExampleNumberForType(regionCode, 2739 i18n.phonenumbers.PhoneNumberType.FIXED_LINE); 2740}; 2741 2742 2743/** 2744 * Gets a valid number for the specified region and number type. 2745 * 2746 * @param {string} regionCode the region for which an example number is needed. 2747 * @param {i18n.phonenumbers.PhoneNumberType} type the type of number that is 2748 * needed. 2749 * @return {i18n.phonenumbers.PhoneNumber} a valid number for the specified 2750 * region and type. Returns null when the metadata does not contain such 2751 * information or if an invalid region or region 001 was entered. 2752 * For 001 (representing non-geographical numbers), call 2753 * {@link #getExampleNumberForNonGeoEntity} instead. 2754 */ 2755i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumberForType = 2756 function(regionCode, type) { 2757 2758 // Check the region code is valid. 2759 if (!this.isValidRegionCode_(regionCode)) { 2760 return null; 2761 } 2762 /** @type {i18n.phonenumbers.PhoneNumberDesc} */ 2763 var desc = i18n.phonenumbers.PhoneNumberUtil.getNumberDescByType_( 2764 this.getMetadataForRegion(regionCode), type); 2765 try { 2766 if (desc.hasExampleNumber()) { 2767 return this.parse(desc.getExampleNumber(), regionCode); 2768 } 2769 } catch (e) { 2770 } 2771 return null; 2772}; 2773 2774 2775/** 2776 * Gets a valid number for the specified country calling code for a 2777 * non-geographical entity. 2778 * 2779 * @param {number} countryCallingCode the country calling code for a 2780 * non-geographical entity. 2781 * @return {i18n.phonenumbers.PhoneNumber} a valid number for the 2782 * non-geographical entity. Returns null when the metadata does not contain 2783 * such information, or the country calling code passed in does not belong 2784 * to a non-geographical entity. 2785 */ 2786i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumberForNonGeoEntity = 2787 function(countryCallingCode) { 2788 /** @type {i18n.phonenumbers.PhoneMetadata} */ 2789 var metadata = 2790 this.getMetadataForNonGeographicalRegion(countryCallingCode); 2791 if (metadata != null) { 2792 /** @type {!i18n.phonenumbers.PhoneNumberDesc|undefined} */ 2793 var numberTypeWithExampleNumber = [ 2794 metadata.getMobile(), metadata.getTollFree(), metadata.getSharedCost(), 2795 metadata.getVoip(), metadata.getVoicemail(), metadata.getUan(), 2796 metadata.getPremiumRate() 2797 ].find(function(desc, index) { 2798 return desc.hasExampleNumber(); 2799 }); 2800 if (numberTypeWithExampleNumber !== undefined) { 2801 try { 2802 return this.parse('+' + countryCallingCode + 2803 numberTypeWithExampleNumber.getExampleNumber(), 'ZZ'); 2804 } catch (e) { 2805 } 2806 } 2807 } 2808 return null; 2809}; 2810 2811 2812/** 2813 * Gets the formatted extension of a phone number, if the phone number had an 2814 * extension specified. If not, it returns an empty string. 2815 * 2816 * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber that might have 2817 * an extension. 2818 * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the 2819 * region that we think this number is from. 2820 * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the 2821 * phone number should be formatted into. 2822 * @return {string} the formatted extension if any. 2823 * @private 2824 */ 2825i18n.phonenumbers.PhoneNumberUtil.prototype.maybeGetFormattedExtension_ = 2826 function(number, metadata, numberFormat) { 2827 2828 if (!number.hasExtension() || number.getExtension().length == 0) { 2829 return ''; 2830 } else { 2831 if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.RFC3966) { 2832 return i18n.phonenumbers.PhoneNumberUtil.RFC3966_EXTN_PREFIX_ + 2833 number.getExtension(); 2834 } else { 2835 if (metadata.hasPreferredExtnPrefix()) { 2836 return metadata.getPreferredExtnPrefix() + 2837 number.getExtensionOrDefault(); 2838 } else { 2839 return i18n.phonenumbers.PhoneNumberUtil.DEFAULT_EXTN_PREFIX_ + 2840 number.getExtensionOrDefault(); 2841 } 2842 } 2843 } 2844}; 2845 2846 2847/** 2848 * @param {i18n.phonenumbers.PhoneMetadata} metadata 2849 * @param {i18n.phonenumbers.PhoneNumberType} type 2850 * @return {i18n.phonenumbers.PhoneNumberDesc} 2851 * @private 2852 */ 2853i18n.phonenumbers.PhoneNumberUtil.getNumberDescByType_ = 2854 function(metadata, type) { 2855 2856 switch (type) { 2857 case i18n.phonenumbers.PhoneNumberType.PREMIUM_RATE: 2858 return metadata.getPremiumRate(); 2859 case i18n.phonenumbers.PhoneNumberType.TOLL_FREE: 2860 return metadata.getTollFree(); 2861 case i18n.phonenumbers.PhoneNumberType.MOBILE: 2862 return metadata.getMobile(); 2863 case i18n.phonenumbers.PhoneNumberType.FIXED_LINE: 2864 case i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE: 2865 return metadata.getFixedLine(); 2866 case i18n.phonenumbers.PhoneNumberType.SHARED_COST: 2867 return metadata.getSharedCost(); 2868 case i18n.phonenumbers.PhoneNumberType.VOIP: 2869 return metadata.getVoip(); 2870 case i18n.phonenumbers.PhoneNumberType.PERSONAL_NUMBER: 2871 return metadata.getPersonalNumber(); 2872 case i18n.phonenumbers.PhoneNumberType.PAGER: 2873 return metadata.getPager(); 2874 case i18n.phonenumbers.PhoneNumberType.UAN: 2875 return metadata.getUan(); 2876 case i18n.phonenumbers.PhoneNumberType.VOICEMAIL: 2877 return metadata.getVoicemail(); 2878 default: 2879 return metadata.getGeneralDesc(); 2880 } 2881}; 2882 2883 2884/** 2885 * Gets the type of a valid phone number. 2886 * 2887 * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want 2888 * to know the type. 2889 * @return {i18n.phonenumbers.PhoneNumberType} the type of the phone number, or 2890 * UNKNOWN if it is invalid. 2891 */ 2892i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberType = 2893 function(number) { 2894 2895 /** @type {?string} */ 2896 var regionCode = this.getRegionCodeForNumber(number); 2897 /** @type {i18n.phonenumbers.PhoneMetadata} */ 2898 var metadata = this.getMetadataForRegionOrCallingCode_( 2899 number.getCountryCodeOrDefault(), regionCode); 2900 if (metadata == null) { 2901 return i18n.phonenumbers.PhoneNumberType.UNKNOWN; 2902 } 2903 /** @type {string} */ 2904 var nationalSignificantNumber = this.getNationalSignificantNumber(number); 2905 return this.getNumberTypeHelper_(nationalSignificantNumber, metadata); 2906}; 2907 2908 2909/** 2910 * @param {string} nationalNumber 2911 * @param {i18n.phonenumbers.PhoneMetadata} metadata 2912 * @return {i18n.phonenumbers.PhoneNumberType} 2913 * @private 2914 */ 2915i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberTypeHelper_ = 2916 function(nationalNumber, metadata) { 2917 2918 if (!this.isNumberMatchingDesc_(nationalNumber, metadata.getGeneralDesc())) { 2919 return i18n.phonenumbers.PhoneNumberType.UNKNOWN; 2920 } 2921 2922 if (this.isNumberMatchingDesc_(nationalNumber, metadata.getPremiumRate())) { 2923 return i18n.phonenumbers.PhoneNumberType.PREMIUM_RATE; 2924 } 2925 if (this.isNumberMatchingDesc_(nationalNumber, metadata.getTollFree())) { 2926 return i18n.phonenumbers.PhoneNumberType.TOLL_FREE; 2927 } 2928 if (this.isNumberMatchingDesc_(nationalNumber, metadata.getSharedCost())) { 2929 return i18n.phonenumbers.PhoneNumberType.SHARED_COST; 2930 } 2931 if (this.isNumberMatchingDesc_(nationalNumber, metadata.getVoip())) { 2932 return i18n.phonenumbers.PhoneNumberType.VOIP; 2933 } 2934 if (this.isNumberMatchingDesc_(nationalNumber, 2935 metadata.getPersonalNumber())) { 2936 return i18n.phonenumbers.PhoneNumberType.PERSONAL_NUMBER; 2937 } 2938 if (this.isNumberMatchingDesc_(nationalNumber, metadata.getPager())) { 2939 return i18n.phonenumbers.PhoneNumberType.PAGER; 2940 } 2941 if (this.isNumberMatchingDesc_(nationalNumber, metadata.getUan())) { 2942 return i18n.phonenumbers.PhoneNumberType.UAN; 2943 } 2944 if (this.isNumberMatchingDesc_(nationalNumber, metadata.getVoicemail())) { 2945 return i18n.phonenumbers.PhoneNumberType.VOICEMAIL; 2946 } 2947 2948 /** @type {boolean} */ 2949 var isFixedLine = this.isNumberMatchingDesc_(nationalNumber, metadata 2950 .getFixedLine()); 2951 if (isFixedLine) { 2952 if (metadata.getSameMobileAndFixedLinePattern()) { 2953 return i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE; 2954 } else if (this.isNumberMatchingDesc_(nationalNumber, 2955 metadata.getMobile())) { 2956 return i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE; 2957 } 2958 return i18n.phonenumbers.PhoneNumberType.FIXED_LINE; 2959 } 2960 // Otherwise, test to see if the number is mobile. Only do this if certain 2961 // that the patterns for mobile and fixed line aren't the same. 2962 if (!metadata.getSameMobileAndFixedLinePattern() && 2963 this.isNumberMatchingDesc_(nationalNumber, metadata.getMobile())) { 2964 return i18n.phonenumbers.PhoneNumberType.MOBILE; 2965 } 2966 return i18n.phonenumbers.PhoneNumberType.UNKNOWN; 2967}; 2968 2969 2970/** 2971 * Returns the metadata for the given region code or {@code null} if the region 2972 * code is invalid or unknown. 2973 * 2974 * @param {?string} regionCode 2975 * @return {?i18n.phonenumbers.PhoneMetadata} 2976 */ 2977i18n.phonenumbers.PhoneNumberUtil.prototype.getMetadataForRegion = 2978 function(regionCode) { 2979 2980 if (regionCode == null) { 2981 return null; 2982 } 2983 regionCode = regionCode.toUpperCase(); 2984 /** @type {i18n.phonenumbers.PhoneMetadata} */ 2985 var metadata = this.regionToMetadataMap[regionCode]; 2986 if (metadata == null) { 2987 /** @type {goog.proto2.PbLiteSerializer} */ 2988 var serializer = new goog.proto2.PbLiteSerializer(); 2989 /** @type {Array} */ 2990 var metadataSerialized = 2991 i18n.phonenumbers.metadata.countryToMetadata[regionCode]; 2992 if (metadataSerialized == null) { 2993 return null; 2994 } 2995 metadata = /** @type {i18n.phonenumbers.PhoneMetadata} */ ( 2996 serializer.deserialize(i18n.phonenumbers.PhoneMetadata.getDescriptor(), 2997 metadataSerialized)); 2998 this.regionToMetadataMap[regionCode] = metadata; 2999 } 3000 return metadata; 3001}; 3002 3003 3004/** 3005 * @param {number} countryCallingCode 3006 * @return {?i18n.phonenumbers.PhoneMetadata} 3007 */ 3008i18n.phonenumbers.PhoneNumberUtil.prototype. 3009 getMetadataForNonGeographicalRegion = function(countryCallingCode) { 3010 3011 return this.getMetadataForRegion('' + countryCallingCode); 3012}; 3013 3014 3015/** 3016 * @param {string} nationalNumber 3017 * @param {i18n.phonenumbers.PhoneNumberDesc} numberDesc 3018 * @return {boolean} 3019 * @private 3020 */ 3021i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberMatchingDesc_ = 3022 function(nationalNumber, numberDesc) { 3023 // Check if any possible number lengths are present; if so, we use them to 3024 // avoid checking the validation pattern if they don't match. If they are 3025 // absent, this means they match the general description, which we have 3026 // already checked before a specific number type. 3027 var actualLength = nationalNumber.length; 3028 if (numberDesc.possibleLengthCount() > 0 && 3029 numberDesc.possibleLengthArray().indexOf(actualLength) == -1) { 3030 return false; 3031 } 3032 return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely( 3033 numberDesc.getNationalNumberPatternOrDefault(), nationalNumber); 3034}; 3035 3036 3037/** 3038 * Tests whether a phone number matches a valid pattern. Note this doesn't 3039 * verify the number is actually in use, which is impossible to tell by just 3040 * looking at a number itself. 3041 * It only verifies whether the parsed, canonicalised number is valid: not 3042 * whether a particular series of digits entered by the user is diallable from 3043 * the region provided when parsing. For example, the number +41 (0) 78 927 2696 3044 * can be parsed into a number with country code "41" and national significant 3045 * number "789272696". This is valid, while the original string is not 3046 * diallable. 3047 * 3048 * @param {!i18n.phonenumbers.PhoneNumber} number the phone number that we want 3049 * to validate. 3050 * @return {boolean} a boolean that indicates whether the number is of a valid 3051 * pattern. 3052 */ 3053i18n.phonenumbers.PhoneNumberUtil.prototype.isValidNumber = function(number) { 3054 /** @type {?string} */ 3055 var regionCode = this.getRegionCodeForNumber(number); 3056 return this.isValidNumberForRegion(number, regionCode); 3057}; 3058 3059 3060/** 3061 * Tests whether a phone number is valid for a certain region. Note this doesn't 3062 * verify the number is actually in use, which is impossible to tell by just 3063 * looking at a number itself. If the country calling code is not the same as 3064 * the country calling code for the region, this immediately exits with false. 3065 * After this, the specific number pattern rules for the region are examined. 3066 * This is useful for determining for example whether a particular number is 3067 * valid for Canada, rather than just a valid NANPA number. 3068 * Warning: In most cases, you want to use {@link #isValidNumber} instead. For 3069 * example, this method will mark numbers from British Crown dependencies such 3070 * as the Isle of Man as invalid for the region "GB" (United Kingdom), since it 3071 * has its own region code, "IM", which may be undesirable. 3072 * 3073 * @param {!i18n.phonenumbers.PhoneNumber} number the phone number that we want 3074 * to validate. 3075 * @param {?string} regionCode the region that we want to validate the phone 3076 * number for. 3077 * @return {boolean} a boolean that indicates whether the number is of a valid 3078 * pattern. 3079 */ 3080i18n.phonenumbers.PhoneNumberUtil.prototype.isValidNumberForRegion = 3081 function(number, regionCode) { 3082 3083 /** @type {number} */ 3084 var countryCode = number.getCountryCodeOrDefault(); 3085 /** @type {i18n.phonenumbers.PhoneMetadata} */ 3086 var metadata = 3087 this.getMetadataForRegionOrCallingCode_(countryCode, regionCode); 3088 if (metadata == null || 3089 (i18n.phonenumbers.PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY != 3090 regionCode && 3091 countryCode != this.getCountryCodeForValidRegion_(regionCode))) { 3092 // Either the region code was invalid, or the country calling code for this 3093 // number does not match that of the region code. 3094 return false; 3095 } 3096 /** @type {string} */ 3097 var nationalSignificantNumber = this.getNationalSignificantNumber(number); 3098 3099 return this.getNumberTypeHelper_(nationalSignificantNumber, metadata) != 3100 i18n.phonenumbers.PhoneNumberType.UNKNOWN; 3101}; 3102 3103 3104/** 3105 * Returns the region where a phone number is from. This could be used for 3106 * geocoding at the region level. Only guarantees correct results for valid, 3107 * full numbers (not short-codes, or invalid numbers). 3108 * 3109 * @param {?i18n.phonenumbers.PhoneNumber} number the phone number whose origin 3110 * we want to know. 3111 * @return {?string} the region where the phone number is from, or null 3112 * if no region matches this calling code. 3113 */ 3114i18n.phonenumbers.PhoneNumberUtil.prototype.getRegionCodeForNumber = 3115 function(number) { 3116 3117 if (number == null) { 3118 return null; 3119 } 3120 /** @type {number} */ 3121 var countryCode = number.getCountryCodeOrDefault(); 3122 /** @type {Array.<string>} */ 3123 var regions = 3124 i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[countryCode]; 3125 if (regions == null) { 3126 return null; 3127 } 3128 if (regions.length == 1) { 3129 return regions[0]; 3130 } else { 3131 return this.getRegionCodeForNumberFromRegionList_(number, regions); 3132 } 3133}; 3134 3135 3136/** 3137 * @param {!i18n.phonenumbers.PhoneNumber} number 3138 * @param {Array.<string>} regionCodes 3139 * @return {?string} 3140 * @private 3141 */ 3142i18n.phonenumbers.PhoneNumberUtil.prototype. 3143 getRegionCodeForNumberFromRegionList_ = function(number, regionCodes) { 3144 3145 /** @type {string} */ 3146 var nationalNumber = this.getNationalSignificantNumber(number); 3147 /** @type {string} */ 3148 var regionCode; 3149 /** @type {number} */ 3150 var regionCodesLength = regionCodes.length; 3151 for (var i = 0; i < regionCodesLength; i++) { 3152 regionCode = regionCodes[i]; 3153 // If leadingDigits is present, use this. Otherwise, do full validation. 3154 // Metadata cannot be null because the region codes come from the country 3155 // calling code map. 3156 /** @type {i18n.phonenumbers.PhoneMetadata} */ 3157 var metadata = this.getMetadataForRegion(regionCode); 3158 if (metadata.hasLeadingDigits()) { 3159 if (nationalNumber.search(metadata.getLeadingDigits()) == 0) { 3160 return regionCode; 3161 } 3162 } else if (this.getNumberTypeHelper_(nationalNumber, metadata) != 3163 i18n.phonenumbers.PhoneNumberType.UNKNOWN) { 3164 return regionCode; 3165 } 3166 } 3167 return null; 3168}; 3169 3170 3171/** 3172 * Returns the region code that matches the specific country calling code. In 3173 * the case of no region code being found, ZZ will be returned. In the case of 3174 * multiple regions, the one designated in the metadata as the 'main' region for 3175 * this calling code will be returned. 3176 * 3177 * @param {number} countryCallingCode the country calling code. 3178 * @return {string} 3179 */ 3180i18n.phonenumbers.PhoneNumberUtil.prototype.getRegionCodeForCountryCode = 3181 function(countryCallingCode) { 3182 3183 /** @type {Array.<string>} */ 3184 var regionCodes = 3185 i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[countryCallingCode]; 3186 return regionCodes == null ? 3187 i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_ : regionCodes[0]; 3188}; 3189 3190 3191/** 3192 * Returns a list with the region codes that match the specific country calling 3193 * code. For non-geographical country calling codes, the region code 001 is 3194 * returned. Also, in the case of no region code being found, an empty list is 3195 * returned. 3196 * 3197 * @param {number} countryCallingCode the country calling code. 3198 * @return {!Array.<string>} 3199 */ 3200i18n.phonenumbers.PhoneNumberUtil.prototype.getRegionCodesForCountryCode = 3201 function(countryCallingCode) { 3202 3203 /** @type {Array.<string>} */ 3204 var regionCodes = 3205 i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[countryCallingCode]; 3206 return regionCodes == null ? [] : regionCodes; 3207}; 3208 3209 3210/** 3211 * Returns the country calling code for a specific region. For example, this 3212 * would be 1 for the United States, and 64 for New Zealand. 3213 * 3214 * @param {?string} regionCode the region that we want to get the country 3215 * calling code for. 3216 * @return {number} the country calling code for the region denoted by 3217 * regionCode. 3218 */ 3219i18n.phonenumbers.PhoneNumberUtil.prototype.getCountryCodeForRegion = 3220 function(regionCode) { 3221 3222 if (!this.isValidRegionCode_(regionCode)) { 3223 return 0; 3224 } 3225 return this.getCountryCodeForValidRegion_(regionCode); 3226}; 3227 3228 3229/** 3230 * Returns the country calling code for a specific region. For example, this 3231 * would be 1 for the United States, and 64 for New Zealand. Assumes the region 3232 * is already valid. 3233 * 3234 * @param {?string} regionCode the region that we want to get the country 3235 * calling code for. 3236 * @return {number} the country calling code for the region denoted by 3237 * regionCode. 3238 * @throws {Error} if the region is invalid 3239 * @private 3240 */ 3241i18n.phonenumbers.PhoneNumberUtil.prototype.getCountryCodeForValidRegion_ = 3242 function(regionCode) { 3243 3244 /** @type {i18n.phonenumbers.PhoneMetadata} */ 3245 var metadata = this.getMetadataForRegion(regionCode); 3246 if (metadata == null) { 3247 throw new Error('Invalid region code: ' + regionCode); 3248 } 3249 return metadata.getCountryCodeOrDefault(); 3250}; 3251 3252 3253/** 3254 * Returns the national dialling prefix for a specific region. For example, this 3255 * would be 1 for the United States, and 0 for New Zealand. Set stripNonDigits 3256 * to true to strip symbols like '~' (which indicates a wait for a dialling 3257 * tone) from the prefix returned. If no national prefix is present, we return 3258 * null. 3259 * 3260 * <p>Warning: Do not use this method for do-your-own formatting - for some 3261 * regions, the national dialling prefix is used only for certain types of 3262 * numbers. Use the library's formatting functions to prefix the national prefix 3263 * when required. 3264 * 3265 * @param {?string} regionCode the region that we want to get the dialling 3266 * prefix for. 3267 * @param {boolean} stripNonDigits true to strip non-digits from the national 3268 * dialling prefix. 3269 * @return {?string} the dialling prefix for the region denoted by 3270 * regionCode. 3271 */ 3272i18n.phonenumbers.PhoneNumberUtil.prototype.getNddPrefixForRegion = function( 3273 regionCode, stripNonDigits) { 3274 /** @type {i18n.phonenumbers.PhoneMetadata} */ 3275 var metadata = this.getMetadataForRegion(regionCode); 3276 if (metadata == null) { 3277 return null; 3278 } 3279 /** @type {string} */ 3280 var nationalPrefix = metadata.getNationalPrefixOrDefault(); 3281 // If no national prefix was found, we return null. 3282 if (nationalPrefix.length == 0) { 3283 return null; 3284 } 3285 if (stripNonDigits) { 3286 // Note: if any other non-numeric symbols are ever used in national 3287 // prefixes, these would have to be removed here as well. 3288 nationalPrefix = nationalPrefix.replace('~', ''); 3289 } 3290 return nationalPrefix; 3291}; 3292 3293 3294/** 3295 * Checks if this is a region under the North American Numbering Plan 3296 * Administration (NANPA). 3297 * 3298 * @param {?string} regionCode the CLDR two-letter region code. 3299 * @return {boolean} true if regionCode is one of the regions under NANPA. 3300 */ 3301i18n.phonenumbers.PhoneNumberUtil.prototype.isNANPACountry = function( 3302 regionCode) { 3303 return regionCode != null && 3304 i18n.phonenumbers.metadata 3305 .countryCodeToRegionCodeMap[i18n.phonenumbers.PhoneNumberUtil 3306 .NANPA_COUNTRY_CODE_] 3307 .includes(regionCode.toUpperCase()); 3308}; 3309 3310 3311/** 3312 * Checks if the number is a valid vanity (alpha) number such as 800 MICROSOFT. 3313 * A valid vanity number will start with at least 3 digits and will have three 3314 * or more alpha characters. This does not do region-specific checks - to work 3315 * out if this number is actually valid for a region, it should be parsed and 3316 * methods such as {@link #isPossibleNumberWithReason} and 3317 * {@link #isValidNumber} should be used. 3318 * 3319 * @param {string} number the number that needs to be checked. 3320 * @return {boolean} true if the number is a valid vanity number. 3321 */ 3322i18n.phonenumbers.PhoneNumberUtil.prototype.isAlphaNumber = function(number) { 3323 if (!i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber(number)) { 3324 // Number is too short, or doesn't match the basic phone number pattern. 3325 return false; 3326 } 3327 /** @type {!goog.string.StringBuffer} */ 3328 var strippedNumber = new goog.string.StringBuffer(number); 3329 this.maybeStripExtension(strippedNumber); 3330 return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely( 3331 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_, 3332 strippedNumber.toString()); 3333}; 3334 3335 3336/** 3337 * Convenience wrapper around {@link #isPossibleNumberWithReason}. Instead of 3338 * returning the reason for failure, this method returns true if the number is 3339 * either a possible fully-qualified number (containing the area code and 3340 * country code), or if the number could be a possible local number (with a 3341 * country code, but missing an area code). Local numbers are considered 3342 * possible if they could be possibly dialled in this format: if the area code 3343 * is needed for a call to connect, the number is not considered possible 3344 * without it. 3345 * 3346 * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be 3347 * checked 3348 * @return {boolean} true if the number is possible 3349 */ 3350i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumber = 3351 function(number) { 3352 /** @type {!i18n.phonenumbers.PhoneNumberUtil.ValidationResult} */ 3353 var result = this.isPossibleNumberWithReason(number); 3354 return result == 3355 i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE || 3356 result == 3357 i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE_LOCAL_ONLY; 3358}; 3359 3360 3361/** 3362 * Convenience wrapper around {@link #isPossibleNumberForTypeWithReason}. 3363 * Instead of returning the reason for failure, this method returns true if the 3364 * number is either a possible fully-qualified number (containing the area code 3365 * and country code), or if the number could be a possible local number (with a 3366 * country code, but missing an area code). Local numbers are considered 3367 * possible if they could be possibly dialled in this format: if the area code 3368 * is needed for a call to connect, the number is not considered possible 3369 * without it. 3370 * 3371 * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be 3372 * checked 3373 * @param {i18n.phonenumbers.PhoneNumberType} type the type we are interested in 3374 * @return {boolean} true if the number is possible for this particular type 3375 */ 3376i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberForType = 3377 function(number, type) { 3378 /** @type {!i18n.phonenumbers.PhoneNumberUtil.ValidationResult} */ 3379 var result = this.isPossibleNumberForTypeWithReason(number, type); 3380 return result == 3381 i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE || 3382 result == 3383 i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE_LOCAL_ONLY; 3384}; 3385 3386 3387/** 3388 * Helper method to check a number against possible lengths for this region, 3389 * based on the metadata being passed in, and determine whether it matches, or 3390 * is too short or too long. 3391 * 3392 * @param {string} number 3393 * @param {i18n.phonenumbers.PhoneMetadata} metadata 3394 * @return {i18n.phonenumbers.PhoneNumberUtil.ValidationResult} 3395 * @private 3396 */ 3397i18n.phonenumbers.PhoneNumberUtil.prototype.testNumberLength_ = 3398 function(number, metadata) { 3399 return this.testNumberLengthForType_( 3400 number, metadata, i18n.phonenumbers.PhoneNumberType.UNKNOWN); 3401}; 3402 3403 3404/** 3405 * Helper method to check a number against a particular pattern and determine 3406 * whether it matches, or is too short or too long. 3407 * 3408 * @param {string} number 3409 * @param {i18n.phonenumbers.PhoneMetadata} metadata 3410 * @param {i18n.phonenumbers.PhoneNumberType} type 3411 * @return {i18n.phonenumbers.PhoneNumberUtil.ValidationResult} 3412 * @private 3413 */ 3414i18n.phonenumbers.PhoneNumberUtil.prototype.testNumberLengthForType_ = 3415 function(number, metadata, type) { 3416 var descForType = 3417 i18n.phonenumbers.PhoneNumberUtil.getNumberDescByType_(metadata, type); 3418 // There should always be "possibleLengths" set for every element. This is 3419 // declared in the XML schema which is verified by 3420 // PhoneNumberMetadataSchemaTest. 3421 // For size efficiency, where a sub-description (e.g. fixed-line) has the 3422 // same possibleLengths as the parent, this is missing, so we fall back to 3423 // the general desc (where no numbers of the type exist at all, there is one 3424 // possible length (-1) which is guaranteed not to match the length of any 3425 // real phone number). 3426 var possibleLengths = descForType.possibleLengthCount() == 0 ? 3427 metadata.getGeneralDesc().possibleLengthArray() : 3428 descForType.possibleLengthArray(); 3429 var localLengths = descForType.possibleLengthLocalOnlyArray(); 3430 3431 if (type == i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE) { 3432 if (!i18n.phonenumbers.PhoneNumberUtil.descHasPossibleNumberData_( 3433 i18n.phonenumbers.PhoneNumberUtil.getNumberDescByType_( 3434 metadata, i18n.phonenumbers.PhoneNumberType.FIXED_LINE))) { 3435 // The rare case has been encountered where no fixedLine data is 3436 // available (true for some non-geographical entities), so we just check 3437 // mobile. 3438 return this.testNumberLengthForType_( 3439 number, metadata, i18n.phonenumbers.PhoneNumberType.MOBILE); 3440 } else { 3441 var mobileDesc = i18n.phonenumbers.PhoneNumberUtil.getNumberDescByType_( 3442 metadata, i18n.phonenumbers.PhoneNumberType.MOBILE); 3443 if (i18n.phonenumbers.PhoneNumberUtil.descHasPossibleNumberData_( 3444 mobileDesc)) { 3445 // Merge the mobile data in if there was any. "Concat" creates a new 3446 // array, it doesn't edit possibleLengths in place, so we don't need a 3447 // copy. 3448 // Note that when adding the possible lengths from mobile, we have 3449 // to again check they aren't empty since if they are this indicates 3450 // they are the same as the general desc and should be obtained from 3451 // there. 3452 possibleLengths = possibleLengths.concat( 3453 mobileDesc.possibleLengthCount() == 0 ? 3454 metadata.getGeneralDesc().possibleLengthArray() : 3455 mobileDesc.possibleLengthArray()); 3456 // The current list is sorted; we need to merge in the new list and 3457 // re-sort (duplicates are okay). Sorting isn't so expensive because the 3458 // lists are very small. 3459 possibleLengths.sort(); 3460 3461 if (localLengths.length == 0) { 3462 localLengths = mobileDesc.possibleLengthLocalOnlyArray(); 3463 } else { 3464 localLengths = localLengths.concat( 3465 mobileDesc.possibleLengthLocalOnlyArray()); 3466 localLengths.sort(); 3467 } 3468 } 3469 } 3470 } 3471 // If the type is not supported at all (indicated by the possible lengths 3472 // containing -1 at this point) we return invalid length. 3473 if (possibleLengths[0] == -1) { 3474 return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.INVALID_LENGTH; 3475 } 3476 3477 var actualLength = number.length; 3478 // This is safe because there is never an overlap beween the possible lengths 3479 // and the local-only lengths; this is checked at build time. 3480 if (localLengths.indexOf(actualLength) > -1) { 3481 return i18n.phonenumbers.PhoneNumberUtil.ValidationResult 3482 .IS_POSSIBLE_LOCAL_ONLY; 3483 } 3484 var minimumLength = possibleLengths[0]; 3485 if (minimumLength == actualLength) { 3486 return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE; 3487 } else if (minimumLength > actualLength) { 3488 return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT; 3489 } else if (possibleLengths[possibleLengths.length - 1] < actualLength) { 3490 return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_LONG; 3491 } 3492 // We skip the first element since we've already checked it. 3493 return (possibleLengths.indexOf(actualLength, 1) > -1) ? 3494 i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE : 3495 i18n.phonenumbers.PhoneNumberUtil.ValidationResult.INVALID_LENGTH; 3496}; 3497 3498 3499/** 3500 * Check whether a phone number is a possible number. It provides a more lenient 3501 * check than {@link #isValidNumber} in the following sense: 3502 * <ol> 3503 * <li>It only checks the length of phone numbers. In particular, it doesn't 3504 * check starting digits of the number. 3505 * <li>It doesn't attempt to figure out the type of the number, but uses general 3506 * rules which applies to all types of phone numbers in a region. Therefore, it 3507 * is much faster than isValidNumber. 3508 * <li>For some numbers (particularly fixed-line), many regions have the concept 3509 * of area code, which together with subscriber number constitute the national 3510 * significant number. It is sometimes okay to dial only the subscriber number 3511 * when dialing in the same area. This function will return 3512 * IS_POSSIBLE_LOCAL_ONLY if the subscriber-number-only version is passed in. On 3513 * the other hand, because isValidNumber validates using information on both 3514 * starting digits (for fixed line numbers, that would most likely be area 3515 * codes) and length (obviously includes the length of area codes for fixed line 3516 * numbers), it will return false for the subscriber-number-only version. 3517 * </ol> 3518 * 3519 * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be 3520 * checked 3521 * @return {i18n.phonenumbers.PhoneNumberUtil.ValidationResult} a 3522 * ValidationResult object which indicates whether the number is possible 3523 */ 3524i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberWithReason = 3525 function(number) { 3526 return this.isPossibleNumberForTypeWithReason( 3527 number, i18n.phonenumbers.PhoneNumberType.UNKNOWN); 3528}; 3529 3530 3531/** 3532 * Check whether a phone number is a possible number. It provides a more lenient 3533 * check than {@link #isValidNumber} in the following sense: 3534 * <ol> 3535 * <li>It only checks the length of phone numbers. In particular, it doesn't 3536 * check starting digits of the number. 3537 * <li>For some numbers (particularly fixed-line), many regions have the concept 3538 * of area code, which together with subscriber number constitute the national 3539 * significant number. It is sometimes okay to dial only the subscriber number 3540 * when dialing in the same area. This function will return 3541 * IS_POSSIBLE_LOCAL_ONLY if the subscriber-number-only version is passed in. On 3542 * the other hand, because isValidNumber validates using information on both 3543 * starting digits (for fixed line numbers, that would most likely be area 3544 * codes) and length (obviously includes the length of area codes for fixed line 3545 * numbers), it will return false for the subscriber-number-only version. 3546 * </ol> 3547 * 3548 * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be 3549 * checked 3550 * @param {i18n.phonenumbers.PhoneNumberType} type the type we are interested in 3551 * @return {i18n.phonenumbers.PhoneNumberUtil.ValidationResult} a 3552 * ValidationResult object which indicates whether the number is possible 3553 */ 3554i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberForTypeWithReason = 3555 function(number, type) { 3556 3557 /** @type {string} */ 3558 var nationalNumber = this.getNationalSignificantNumber(number); 3559 /** @type {number} */ 3560 var countryCode = number.getCountryCodeOrDefault(); 3561 // Note: For regions that share a country calling code, like NANPA numbers, 3562 // we just use the rules from the default region (US in this case) since the 3563 // getRegionCodeForNumber will not work if the number is possible but not 3564 // valid. There is in fact one country calling code (290) where the possible 3565 // number pattern differs between various regions (Saint Helena and Tristan 3566 // da Cunha), but this is handled by putting all possible lengths for any 3567 // country with this country calling code in the metadata for the default 3568 // region in this case. 3569 if (!this.hasValidCountryCallingCode_(countryCode)) { 3570 return i18n.phonenumbers.PhoneNumberUtil.ValidationResult 3571 .INVALID_COUNTRY_CODE; 3572 } 3573 /** @type {string} */ 3574 var regionCode = this.getRegionCodeForCountryCode(countryCode); 3575 // Metadata cannot be null because the country calling code is valid. 3576 /** @type {i18n.phonenumbers.PhoneMetadata} */ 3577 var metadata = 3578 this.getMetadataForRegionOrCallingCode_(countryCode, regionCode); 3579 return this.testNumberLengthForType_(nationalNumber, metadata, type); 3580}; 3581 3582 3583/** 3584 * Check whether a phone number is a possible number given a number in the form 3585 * of a string, and the region where the number could be dialed from. It 3586 * provides a more lenient check than {@link #isValidNumber}. See 3587 * {@link #isPossibleNumber} for details. 3588 * 3589 * <p>This method first parses the number, then invokes 3590 * {@link #isPossibleNumber} with the resultant PhoneNumber object. 3591 * 3592 * @param {string} number the number that needs to be checked, in the form of a 3593 * string. 3594 * @param {string} regionDialingFrom the region that we are expecting the number 3595 * to be dialed from. 3596 * Note this is different from the region where the number belongs. 3597 * For example, the number +1 650 253 0000 is a number that belongs to US. 3598 * When written in this form, it can be dialed from any region. When it is 3599 * written as 00 1 650 253 0000, it can be dialed from any region which uses 3600 * an international dialling prefix of 00. When it is written as 3601 * 650 253 0000, it can only be dialed from within the US, and when written 3602 * as 253 0000, it can only be dialed from within a smaller area in the US 3603 * (Mountain View, CA, to be more specific). 3604 * @return {boolean} true if the number is possible. 3605 */ 3606i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberString = 3607 function(number, regionDialingFrom) { 3608 3609 try { 3610 return this.isPossibleNumber(this.parse(number, regionDialingFrom)); 3611 } catch (e) { 3612 return false; 3613 } 3614}; 3615 3616 3617/** 3618 * Attempts to extract a valid number from a phone number that is too long to be 3619 * valid, and resets the PhoneNumber object passed in to that valid version. If 3620 * no valid number could be extracted, the PhoneNumber object passed in will not 3621 * be modified. 3622 * @param {!i18n.phonenumbers.PhoneNumber} number a PhoneNumber object which 3623 * contains a number that is too long to be valid. 3624 * @return {boolean} true if a valid phone number can be successfully extracted. 3625 */ 3626i18n.phonenumbers.PhoneNumberUtil.prototype.truncateTooLongNumber = 3627 function(number) { 3628 3629 if (this.isValidNumber(number)) { 3630 return true; 3631 } 3632 /** @type {i18n.phonenumbers.PhoneNumber} */ 3633 var numberCopy = number.clone(); 3634 /** @type {number} */ 3635 var nationalNumber = number.getNationalNumberOrDefault(); 3636 do { 3637 nationalNumber = Math.floor(nationalNumber / 10); 3638 numberCopy.setNationalNumber(nationalNumber); 3639 if (nationalNumber == 0 || 3640 this.isPossibleNumberWithReason(numberCopy) == 3641 i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT) { 3642 return false; 3643 } 3644 } while (!this.isValidNumber(numberCopy)); 3645 number.setNationalNumber(nationalNumber); 3646 return true; 3647}; 3648 3649 3650/** 3651 * Extracts country calling code from fullNumber, returns it and places the 3652 * remaining number in nationalNumber. It assumes that the leading plus sign or 3653 * IDD has already been removed. Returns 0 if fullNumber doesn't start with a 3654 * valid country calling code, and leaves nationalNumber unmodified. 3655 * 3656 * @param {!goog.string.StringBuffer} fullNumber 3657 * @param {!goog.string.StringBuffer} nationalNumber 3658 * @return {number} 3659 */ 3660i18n.phonenumbers.PhoneNumberUtil.prototype.extractCountryCode = 3661 function(fullNumber, nationalNumber) { 3662 3663 /** @type {string} */ 3664 var fullNumberStr = fullNumber.toString(); 3665 if ((fullNumberStr.length == 0) || (fullNumberStr.charAt(0) == '0')) { 3666 // Country codes do not begin with a '0'. 3667 return 0; 3668 } 3669 /** @type {number} */ 3670 var potentialCountryCode; 3671 /** @type {number} */ 3672 var numberLength = fullNumberStr.length; 3673 for (var i = 1; 3674 i <= i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE_ && 3675 i <= numberLength; ++i) { 3676 potentialCountryCode = parseInt(fullNumberStr.substring(0, i), 10); 3677 if (potentialCountryCode in 3678 i18n.phonenumbers.metadata.countryCodeToRegionCodeMap) { 3679 nationalNumber.append(fullNumberStr.substring(i)); 3680 return potentialCountryCode; 3681 } 3682 } 3683 return 0; 3684}; 3685 3686 3687/** 3688 * Tries to extract a country calling code from a number. This method will 3689 * return zero if no country calling code is considered to be present. Country 3690 * calling codes are extracted in the following ways: 3691 * <ul> 3692 * <li>by stripping the international dialing prefix of the region the person is 3693 * dialing from, if this is present in the number, and looking at the next 3694 * digits 3695 * <li>by stripping the '+' sign if present and then looking at the next digits 3696 * <li>by comparing the start of the number and the country calling code of the 3697 * default region. If the number is not considered possible for the numbering 3698 * plan of the default region initially, but starts with the country calling 3699 * code of this region, validation will be reattempted after stripping this 3700 * country calling code. If this number is considered a possible number, then 3701 * the first digits will be considered the country calling code and removed as 3702 * such. 3703 * </ul> 3704 * 3705 * It will throw a i18n.phonenumbers.Error if the number starts with a '+' but 3706 * the country calling code supplied after this does not match that of any known 3707 * region. 3708 * 3709 * @param {string} number non-normalized telephone number that we wish to 3710 * extract a country calling code from - may begin with '+'. 3711 * @param {i18n.phonenumbers.PhoneMetadata} defaultRegionMetadata metadata 3712 * about the region this number may be from. 3713 * @param {!goog.string.StringBuffer} nationalNumber a string buffer to store 3714 * the national significant number in, in the case that a country calling 3715 * code was extracted. The number is appended to any existing contents. If 3716 * no country calling code was extracted, this will be left unchanged. 3717 * @param {boolean} keepRawInput true if the country_code_source and 3718 * preferred_carrier_code fields of phoneNumber should be populated. 3719 * @param {i18n.phonenumbers.PhoneNumber} phoneNumber the PhoneNumber object 3720 * where the country_code and country_code_source need to be populated. 3721 * Note the country_code is always populated, whereas country_code_source is 3722 * only populated when keepCountryCodeSource is true. 3723 * @return {number} the country calling code extracted or 0 if none could be 3724 * extracted. 3725 * @throws {Error} 3726 */ 3727i18n.phonenumbers.PhoneNumberUtil.prototype.maybeExtractCountryCode = 3728 function(number, defaultRegionMetadata, nationalNumber, 3729 keepRawInput, phoneNumber) { 3730 3731 if (number.length == 0) { 3732 return 0; 3733 } 3734 /** @type {!goog.string.StringBuffer} */ 3735 var fullNumber = new goog.string.StringBuffer(number); 3736 // Set the default prefix to be something that will never match. 3737 /** @type {?string} */ 3738 var possibleCountryIddPrefix; 3739 if (defaultRegionMetadata != null) { 3740 possibleCountryIddPrefix = defaultRegionMetadata.getInternationalPrefix(); 3741 } 3742 if (possibleCountryIddPrefix == null) { 3743 possibleCountryIddPrefix = 'NonMatch'; 3744 } 3745 3746 /** @type {i18n.phonenumbers.PhoneNumber.CountryCodeSource} */ 3747 var countryCodeSource = this.maybeStripInternationalPrefixAndNormalize( 3748 fullNumber, possibleCountryIddPrefix); 3749 if (keepRawInput) { 3750 phoneNumber.setCountryCodeSource(countryCodeSource); 3751 } 3752 if (countryCodeSource != 3753 i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY) { 3754 if (fullNumber.getLength() <= 3755 i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) { 3756 throw new Error(i18n.phonenumbers.Error.TOO_SHORT_AFTER_IDD); 3757 } 3758 /** @type {number} */ 3759 var potentialCountryCode = this.extractCountryCode(fullNumber, 3760 nationalNumber); 3761 if (potentialCountryCode != 0) { 3762 phoneNumber.setCountryCode(potentialCountryCode); 3763 return potentialCountryCode; 3764 } 3765 3766 // If this fails, they must be using a strange country calling code that we 3767 // don't recognize, or that doesn't exist. 3768 throw new Error(i18n.phonenumbers.Error.INVALID_COUNTRY_CODE); 3769 } else if (defaultRegionMetadata != null) { 3770 // Check to see if the number starts with the country calling code for the 3771 // default region. If so, we remove the country calling code, and do some 3772 // checks on the validity of the number before and after. 3773 /** @type {number} */ 3774 var defaultCountryCode = defaultRegionMetadata.getCountryCodeOrDefault(); 3775 /** @type {string} */ 3776 var defaultCountryCodeString = '' + defaultCountryCode; 3777 /** @type {string} */ 3778 var normalizedNumber = fullNumber.toString(); 3779 if (goog.string.startsWith(normalizedNumber, defaultCountryCodeString)) { 3780 /** @type {!goog.string.StringBuffer} */ 3781 var potentialNationalNumber = new goog.string.StringBuffer( 3782 normalizedNumber.substring(defaultCountryCodeString.length)); 3783 /** @type {i18n.phonenumbers.PhoneNumberDesc} */ 3784 var generalDesc = defaultRegionMetadata.getGeneralDesc(); 3785 /** @type {!RegExp} */ 3786 var validNumberPattern = 3787 new RegExp(generalDesc.getNationalNumberPatternOrDefault()); 3788 // Passing null since we don't need the carrier code. 3789 this.maybeStripNationalPrefixAndCarrierCode( 3790 potentialNationalNumber, defaultRegionMetadata, null); 3791 /** @type {string} */ 3792 var potentialNationalNumberStr = potentialNationalNumber.toString(); 3793 // If the number was not valid before but is valid now, or if it was too 3794 // long before, we consider the number with the country calling code 3795 // stripped to be a better result and keep that instead. 3796 if ((!i18n.phonenumbers.PhoneNumberUtil.matchesEntirely( 3797 validNumberPattern, fullNumber.toString()) && 3798 i18n.phonenumbers.PhoneNumberUtil.matchesEntirely( 3799 validNumberPattern, potentialNationalNumberStr)) || 3800 this.testNumberLength_( 3801 fullNumber.toString(), defaultRegionMetadata) == 3802 i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_LONG) { 3803 nationalNumber.append(potentialNationalNumberStr); 3804 if (keepRawInput) { 3805 phoneNumber.setCountryCodeSource( 3806 i18n.phonenumbers.PhoneNumber.CountryCodeSource 3807 .FROM_NUMBER_WITHOUT_PLUS_SIGN); 3808 } 3809 phoneNumber.setCountryCode(defaultCountryCode); 3810 return defaultCountryCode; 3811 } 3812 } 3813 } 3814 // No country calling code present. 3815 phoneNumber.setCountryCode(0); 3816 return 0; 3817}; 3818 3819 3820/** 3821 * Strips the IDD from the start of the number if present. Helper function used 3822 * by maybeStripInternationalPrefixAndNormalize. 3823 * 3824 * @param {!RegExp} iddPattern the regular expression for the international 3825 * prefix. 3826 * @param {!goog.string.StringBuffer} number the phone number that we wish to 3827 * strip any international dialing prefix from. 3828 * @return {boolean} true if an international prefix was present. 3829 * @private 3830 */ 3831i18n.phonenumbers.PhoneNumberUtil.prototype.parsePrefixAsIdd_ = 3832 function(iddPattern, number) { 3833 3834 /** @type {string} */ 3835 var numberStr = number.toString(); 3836 if (numberStr.search(iddPattern) == 0) { 3837 /** @type {number} */ 3838 var matchEnd = numberStr.match(iddPattern)[0].length; 3839 /** @type {Array.<string>} */ 3840 var matchedGroups = numberStr.substring(matchEnd).match( 3841 i18n.phonenumbers.PhoneNumberUtil.CAPTURING_DIGIT_PATTERN); 3842 if (matchedGroups && matchedGroups[1] != null && 3843 matchedGroups[1].length > 0) { 3844 /** @type {string} */ 3845 var normalizedGroup = 3846 i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly( 3847 matchedGroups[1]); 3848 if (normalizedGroup == '0') { 3849 return false; 3850 } 3851 } 3852 number.clear(); 3853 number.append(numberStr.substring(matchEnd)); 3854 return true; 3855 } 3856 return false; 3857}; 3858 3859 3860/** 3861 * Strips any international prefix (such as +, 00, 011) present in the number 3862 * provided, normalizes the resulting number, and indicates if an international 3863 * prefix was present. 3864 * 3865 * @param {!goog.string.StringBuffer} number the non-normalized telephone number 3866 * that we wish to strip any international dialing prefix from. 3867 * @param {string} possibleIddPrefix the international direct dialing prefix 3868 * from the region we think this number may be dialed in. 3869 * @return {i18n.phonenumbers.PhoneNumber.CountryCodeSource} the corresponding 3870 * CountryCodeSource if an international dialing prefix could be removed 3871 * from the number, otherwise CountryCodeSource.FROM_DEFAULT_COUNTRY if 3872 * the number did not seem to be in international format. 3873 */ 3874i18n.phonenumbers.PhoneNumberUtil.prototype. 3875 maybeStripInternationalPrefixAndNormalize = function(number, 3876 possibleIddPrefix) { 3877 /** @type {string} */ 3878 var numberStr = number.toString(); 3879 if (numberStr.length == 0) { 3880 return i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY; 3881 } 3882 // Check to see if the number begins with one or more plus signs. 3883 if (i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN 3884 .test(numberStr)) { 3885 numberStr = numberStr.replace( 3886 i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN, ''); 3887 // Can now normalize the rest of the number since we've consumed the '+' 3888 // sign at the start. 3889 number.clear(); 3890 number.append(i18n.phonenumbers.PhoneNumberUtil.normalize(numberStr)); 3891 return i18n.phonenumbers.PhoneNumber.CountryCodeSource 3892 .FROM_NUMBER_WITH_PLUS_SIGN; 3893 } 3894 // Attempt to parse the first digits as an international prefix. 3895 /** @type {!RegExp} */ 3896 var iddPattern = new RegExp(possibleIddPrefix); 3897 i18n.phonenumbers.PhoneNumberUtil.normalizeSB_(number); 3898 return this.parsePrefixAsIdd_(iddPattern, number) ? 3899 i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD : 3900 i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY; 3901}; 3902 3903 3904/** 3905 * Strips any national prefix (such as 0, 1) present in the number provided. 3906 * 3907 * @param {!goog.string.StringBuffer} number the normalized telephone number 3908 * that we wish to strip any national dialing prefix from. 3909 * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the 3910 * region that we think this number is from. 3911 * @param {goog.string.StringBuffer} carrierCode a place to insert the carrier 3912 * code if one is extracted. 3913 * @return {boolean} true if a national prefix or carrier code (or both) could 3914 * be extracted. 3915 */ 3916i18n.phonenumbers.PhoneNumberUtil.prototype. 3917 maybeStripNationalPrefixAndCarrierCode = function(number, metadata, 3918 carrierCode) { 3919 /** @type {string} */ 3920 var numberStr = number.toString(); 3921 /** @type {number} */ 3922 var numberLength = numberStr.length; 3923 /** @type {?string} */ 3924 var possibleNationalPrefix = metadata.getNationalPrefixForParsing(); 3925 if (numberLength == 0 || possibleNationalPrefix == null || 3926 possibleNationalPrefix.length == 0) { 3927 // Early return for numbers of zero length. 3928 return false; 3929 } 3930 // Attempt to parse the first digits as a national prefix. 3931 /** @type {!RegExp} */ 3932 var prefixPattern = new RegExp('^(?:' + possibleNationalPrefix + ')'); 3933 /** @type {Array.<string>} */ 3934 var prefixMatcher = prefixPattern.exec(numberStr); 3935 if (prefixMatcher) { 3936 /** @type {!RegExp} */ 3937 var nationalNumberRule = new RegExp( 3938 metadata.getGeneralDesc().getNationalNumberPatternOrDefault()); 3939 // Check if the original number is viable. 3940 /** @type {boolean} */ 3941 var isViableOriginalNumber = 3942 i18n.phonenumbers.PhoneNumberUtil.matchesEntirely( 3943 nationalNumberRule, numberStr); 3944 // prefixMatcher[numOfGroups] == null implies nothing was captured by the 3945 // capturing groups in possibleNationalPrefix; therefore, no transformation 3946 // is necessary, and we just remove the national prefix. 3947 /** @type {number} */ 3948 var numOfGroups = prefixMatcher.length - 1; 3949 /** @type {?string} */ 3950 var transformRule = metadata.getNationalPrefixTransformRule(); 3951 /** @type {boolean} */ 3952 var noTransform = transformRule == null || transformRule.length == 0 || 3953 prefixMatcher[numOfGroups] == null || 3954 prefixMatcher[numOfGroups].length == 0; 3955 if (noTransform) { 3956 // If the original number was viable, and the resultant number is not, 3957 // we return. 3958 if (isViableOriginalNumber && 3959 !i18n.phonenumbers.PhoneNumberUtil.matchesEntirely( 3960 nationalNumberRule, 3961 numberStr.substring(prefixMatcher[0].length))) { 3962 return false; 3963 } 3964 if (carrierCode != null && 3965 numOfGroups > 0 && prefixMatcher[numOfGroups] != null) { 3966 carrierCode.append(prefixMatcher[1]); 3967 } 3968 number.set(numberStr.substring(prefixMatcher[0].length)); 3969 return true; 3970 } else { 3971 // Check that the resultant number is still viable. If not, return. Check 3972 // this by copying the string buffer and making the transformation on the 3973 // copy first. 3974 /** @type {string} */ 3975 var transformedNumber; 3976 transformedNumber = numberStr.replace(prefixPattern, transformRule); 3977 if (isViableOriginalNumber && 3978 !i18n.phonenumbers.PhoneNumberUtil.matchesEntirely( 3979 nationalNumberRule, transformedNumber)) { 3980 return false; 3981 } 3982 if (carrierCode != null && numOfGroups > 0) { 3983 carrierCode.append(prefixMatcher[1]); 3984 } 3985 number.set(transformedNumber); 3986 return true; 3987 } 3988 } 3989 return false; 3990}; 3991 3992 3993/** 3994 * Strips any extension (as in, the part of the number dialled after the call is 3995 * connected, usually indicated with extn, ext, x or similar) from the end of 3996 * the number, and returns it. 3997 * 3998 * @param {!goog.string.StringBuffer} number the non-normalized telephone number 3999 * that we wish to strip the extension from. 4000 * @return {string} the phone extension. 4001 */ 4002i18n.phonenumbers.PhoneNumberUtil.prototype.maybeStripExtension = 4003 function(number) { 4004 4005 /** @type {string} */ 4006 var numberStr = number.toString(); 4007 /** @type {number} */ 4008 var mStart = 4009 numberStr.search(i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_); 4010 // If we find a potential extension, and the number preceding this is a viable 4011 // number, we assume it is an extension. 4012 if (mStart >= 0 && i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber( 4013 numberStr.substring(0, mStart))) { 4014 // The numbers are captured into groups in the regular expression. 4015 /** @type {Array.<string>} */ 4016 var matchedGroups = 4017 numberStr.match(i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_); 4018 /** @type {number} */ 4019 var matchedGroupsLength = matchedGroups.length; 4020 for (var i = 1; i < matchedGroupsLength; ++i) { 4021 if (matchedGroups[i] != null && matchedGroups[i].length > 0) { 4022 // We go through the capturing groups until we find one that captured 4023 // some digits. If none did, then we will return the empty string. 4024 number.clear(); 4025 number.append(numberStr.substring(0, mStart)); 4026 return matchedGroups[i]; 4027 } 4028 } 4029 } 4030 return ''; 4031}; 4032 4033 4034/** 4035 * Checks to see that the region code used is valid, or if it is not valid, that 4036 * the number to parse starts with a + symbol so that we can attempt to infer 4037 * the region from the number. 4038 * @param {string} numberToParse number that we are attempting to parse. 4039 * @param {?string} defaultRegion region that we are expecting the number to be 4040 * from. 4041 * @return {boolean} false if it cannot use the region provided and the region 4042 * cannot be inferred. 4043 * @private 4044 */ 4045i18n.phonenumbers.PhoneNumberUtil.prototype.checkRegionForParsing_ = function( 4046 numberToParse, defaultRegion) { 4047 // If the number is null or empty, we can't infer the region. 4048 return this.isValidRegionCode_(defaultRegion) || 4049 (numberToParse != null && numberToParse.length > 0 && 4050 i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN.test( 4051 numberToParse)); 4052}; 4053 4054 4055/** 4056 * Parses a string and returns it as a phone number in proto buffer format. The 4057 * method is quite lenient and looks for a number in the input text (raw input) 4058 * and does not check whether the string is definitely only a phone number. To 4059 * do this, it ignores punctuation and white-space, as well as any text before 4060 * the number (e.g. a leading "Tel: ") and trims the non-number bits. It will 4061 * accept a number in any format (E164, national, international etc), assuming 4062 * it can be interpreted with the defaultRegion supplied. It also attempts to 4063 * convert any alpha characters into digits if it thinks this is a vanity number 4064 * of the type "1800 MICROSOFT". 4065 * 4066 * Note this method canonicalizes the phone number such that different 4067 * representations can be easily compared, no matter what form it was originally 4068 * entered in (e.g. national, international). If you want to record context 4069 * about the number being parsed, such as the raw input that was entered, how 4070 * the country code was derived etc. then call parseAndKeepRawInput() instead. 4071 * 4072 * This method will throw a {@link i18n.phonenumbers.Error} if the number is not 4073 * considered to be a possible number. Note that validation of whether the 4074 * number is actually a valid number for a particular region is not performed. 4075 * This can be done separately with {@link #isValidNumber}. 4076 * 4077 * @param {?string} numberToParse number that we are attempting to parse. This 4078 * can contain formatting such as +, ( and -, as well as a phone number 4079 * extension. It can also be provided in RFC3966 format. 4080 * @param {?string} defaultRegion region that we are expecting the number to be 4081 * from. This is only used if the number being parsed is not written in 4082 * international format. The country_code for the number in this case would 4083 * be stored as that of the default region supplied. If the number is 4084 * guaranteed to start with a '+' followed by the country calling code, then 4085 * 'ZZ' or null can be supplied. 4086 * @return {!i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled 4087 * with the parsed number. 4088 * @throws {Error} if the string is not considered to be a 4089 * viable phone number (e.g. too few or too many digits) or if no default 4090 * region was supplied and the number is not in international format (does 4091 * not start with +). 4092 */ 4093i18n.phonenumbers.PhoneNumberUtil.prototype.parse = function(numberToParse, 4094 defaultRegion) { 4095 return this.parseHelper_(numberToParse, defaultRegion, false, true); 4096}; 4097 4098 4099/** 4100 * Parses a string and returns it in proto buffer format. This method differs 4101 * from {@link #parse} in that it always populates the raw_input field of the 4102 * protocol buffer with numberToParse as well as the country_code_source field. 4103 * 4104 * @param {string} numberToParse number that we are attempting to parse. This 4105 * can contain formatting such as +, ( and -, as well as a phone number 4106 * extension. 4107 * @param {?string} defaultRegion region that we are expecting the number to be 4108 * from. This is only used if the number being parsed is not written in 4109 * international format. The country calling code for the number in this 4110 * case would be stored as that of the default region supplied. 4111 * @return {!i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled 4112 * with the parsed number. 4113 * @throws {Error} if the string is not considered to be a 4114 * viable phone number or if no default region was supplied. 4115 */ 4116i18n.phonenumbers.PhoneNumberUtil.prototype.parseAndKeepRawInput = 4117 function(numberToParse, defaultRegion) { 4118 4119 if (!this.isValidRegionCode_(defaultRegion)) { 4120 if (numberToParse.length > 0 && numberToParse.charAt(0) != 4121 i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) { 4122 throw new Error(i18n.phonenumbers.Error.INVALID_COUNTRY_CODE); 4123 } 4124 } 4125 return this.parseHelper_(numberToParse, defaultRegion, true, true); 4126}; 4127 4128 4129/** 4130 * A helper function to set the values related to leading zeros in a 4131 * PhoneNumber. 4132 * 4133 * @param {string} nationalNumber the number we are parsing. 4134 * @param {i18n.phonenumbers.PhoneNumber} phoneNumber a phone number proto 4135 * buffer to fill in. 4136 * @private 4137 */ 4138i18n.phonenumbers.PhoneNumberUtil.setItalianLeadingZerosForPhoneNumber_ = 4139 function(nationalNumber, phoneNumber) { 4140 if (nationalNumber.length > 1 && nationalNumber.charAt(0) == '0') { 4141 phoneNumber.setItalianLeadingZero(true); 4142 var numberOfLeadingZeros = 1; 4143 // Note that if the national number is all "0"s, the last "0" is not counted 4144 // as a leading zero. 4145 while (numberOfLeadingZeros < nationalNumber.length - 1 && 4146 nationalNumber.charAt(numberOfLeadingZeros) == '0') { 4147 numberOfLeadingZeros++; 4148 } 4149 if (numberOfLeadingZeros != 1) { 4150 phoneNumber.setNumberOfLeadingZeros(numberOfLeadingZeros); 4151 } 4152 } 4153}; 4154 4155 4156/** 4157 * Parses a string and returns it in proto buffer format. This method is the 4158 * same as the public {@link #parse} method, with the exception that it allows 4159 * the default region to be null, for use by {@link #isNumberMatch}. 4160 * 4161 * Note if any new field is added to this method that should always be filled 4162 * in, even when keepRawInput is false, it should also be handled in the 4163 * copyCoreFieldsOnly method. 4164 * 4165 * @param {?string} numberToParse number that we are attempting to parse. This 4166 * can contain formatting such as +, ( and -, as well as a phone number 4167 * extension. 4168 * @param {?string} defaultRegion region that we are expecting the number to be 4169 * from. This is only used if the number being parsed is not written in 4170 * international format. The country calling code for the number in this 4171 * case would be stored as that of the default region supplied. 4172 * @param {boolean} keepRawInput whether to populate the raw_input field of the 4173 * phoneNumber with numberToParse. 4174 * @param {boolean} checkRegion should be set to false if it is permitted for 4175 * the default coregion to be null or unknown ('ZZ'). 4176 * @return {!i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled 4177 * with the parsed number. 4178 * @throws {Error} 4179 * @private 4180 */ 4181i18n.phonenumbers.PhoneNumberUtil.prototype.parseHelper_ = 4182 function(numberToParse, defaultRegion, keepRawInput, checkRegion) { 4183 4184 if (numberToParse == null) { 4185 throw new Error(i18n.phonenumbers.Error.NOT_A_NUMBER); 4186 } else if (numberToParse.length > 4187 i18n.phonenumbers.PhoneNumberUtil.MAX_INPUT_STRING_LENGTH_) { 4188 throw new Error(i18n.phonenumbers.Error.TOO_LONG); 4189 } 4190 4191 /** @type {!goog.string.StringBuffer} */ 4192 var nationalNumber = new goog.string.StringBuffer(); 4193 this.buildNationalNumberForParsing_(numberToParse, nationalNumber); 4194 4195 if (!i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber( 4196 nationalNumber.toString())) { 4197 throw new Error(i18n.phonenumbers.Error.NOT_A_NUMBER); 4198 } 4199 4200 // Check the region supplied is valid, or that the extracted number starts 4201 // with some sort of + sign so the number's region can be determined. 4202 if (checkRegion && 4203 !this.checkRegionForParsing_(nationalNumber.toString(), defaultRegion)) { 4204 throw new Error(i18n.phonenumbers.Error.INVALID_COUNTRY_CODE); 4205 } 4206 4207 /** @type {i18n.phonenumbers.PhoneNumber} */ 4208 var phoneNumber = new i18n.phonenumbers.PhoneNumber(); 4209 if (keepRawInput) { 4210 phoneNumber.setRawInput(numberToParse); 4211 } 4212 // Attempt to parse extension first, since it doesn't require region-specific 4213 // data and we want to have the non-normalised number here. 4214 /** @type {string} */ 4215 var extension = this.maybeStripExtension(nationalNumber); 4216 if (extension.length > 0) { 4217 phoneNumber.setExtension(extension); 4218 } 4219 4220 /** @type {i18n.phonenumbers.PhoneMetadata} */ 4221 var regionMetadata = this.getMetadataForRegion(defaultRegion); 4222 // Check to see if the number is given in international format so we know 4223 // whether this number is from the default region or not. 4224 /** @type {!goog.string.StringBuffer} */ 4225 var normalizedNationalNumber = new goog.string.StringBuffer(); 4226 /** @type {number} */ 4227 var countryCode = 0; 4228 /** @type {string} */ 4229 var nationalNumberStr = nationalNumber.toString(); 4230 try { 4231 countryCode = this.maybeExtractCountryCode(nationalNumberStr, 4232 regionMetadata, normalizedNationalNumber, keepRawInput, phoneNumber); 4233 } catch (e) { 4234 if (e.message == i18n.phonenumbers.Error.INVALID_COUNTRY_CODE && 4235 i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN 4236 .test(nationalNumberStr)) { 4237 // Strip the plus-char, and try again. 4238 nationalNumberStr = nationalNumberStr.replace( 4239 i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN, ''); 4240 countryCode = this.maybeExtractCountryCode(nationalNumberStr, 4241 regionMetadata, normalizedNationalNumber, keepRawInput, phoneNumber); 4242 if (countryCode == 0) { 4243 throw e; 4244 } 4245 } else { 4246 throw e; 4247 } 4248 } 4249 if (countryCode != 0) { 4250 /** @type {string} */ 4251 var phoneNumberRegion = this.getRegionCodeForCountryCode(countryCode); 4252 if (phoneNumberRegion != defaultRegion) { 4253 // Metadata cannot be null because the country calling code is valid. 4254 regionMetadata = this.getMetadataForRegionOrCallingCode_( 4255 countryCode, phoneNumberRegion); 4256 } 4257 } else { 4258 // If no extracted country calling code, use the region supplied instead. 4259 // The national number is just the normalized version of the number we were 4260 // given to parse. 4261 i18n.phonenumbers.PhoneNumberUtil.normalizeSB_(nationalNumber); 4262 normalizedNationalNumber.append(nationalNumber.toString()); 4263 if (defaultRegion != null) { 4264 countryCode = regionMetadata.getCountryCodeOrDefault(); 4265 phoneNumber.setCountryCode(countryCode); 4266 } else if (keepRawInput) { 4267 phoneNumber.clearCountryCodeSource(); 4268 } 4269 } 4270 if (normalizedNationalNumber.getLength() < 4271 i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) { 4272 throw new Error(i18n.phonenumbers.Error.TOO_SHORT_NSN); 4273 } 4274 4275 if (regionMetadata != null) { 4276 /** @type {!goog.string.StringBuffer} */ 4277 var carrierCode = new goog.string.StringBuffer(); 4278 /** @type {!goog.string.StringBuffer} */ 4279 var potentialNationalNumber = 4280 new goog.string.StringBuffer(normalizedNationalNumber.toString()); 4281 this.maybeStripNationalPrefixAndCarrierCode( 4282 potentialNationalNumber, regionMetadata, carrierCode); 4283 // We require that the NSN remaining after stripping the national prefix and 4284 // carrier code be long enough to be a possible length for the region. 4285 // Otherwise, we don't do the stripping, since the original number could be 4286 // a valid short number. 4287 var validationResult = this.testNumberLength_( 4288 potentialNationalNumber.toString(), regionMetadata); 4289 var validationResults = i18n.phonenumbers.PhoneNumberUtil.ValidationResult; 4290 if (validationResult != validationResults.TOO_SHORT && 4291 validationResult != validationResults.IS_POSSIBLE_LOCAL_ONLY && 4292 validationResult != validationResults.INVALID_LENGTH) { 4293 normalizedNationalNumber = potentialNationalNumber; 4294 if (keepRawInput && carrierCode.toString().length > 0) { 4295 phoneNumber.setPreferredDomesticCarrierCode(carrierCode.toString()); 4296 } 4297 } 4298 } 4299 /** @type {string} */ 4300 var normalizedNationalNumberStr = normalizedNationalNumber.toString(); 4301 /** @type {number} */ 4302 var lengthOfNationalNumber = normalizedNationalNumberStr.length; 4303 if (lengthOfNationalNumber < 4304 i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) { 4305 throw new Error(i18n.phonenumbers.Error.TOO_SHORT_NSN); 4306 } 4307 if (lengthOfNationalNumber > 4308 i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_) { 4309 throw new Error(i18n.phonenumbers.Error.TOO_LONG); 4310 } 4311 i18n.phonenumbers.PhoneNumberUtil.setItalianLeadingZerosForPhoneNumber_( 4312 normalizedNationalNumberStr, phoneNumber); 4313 phoneNumber.setNationalNumber(parseInt(normalizedNationalNumberStr, 10)); 4314 return phoneNumber; 4315}; 4316 4317 4318/** 4319 * Converts numberToParse to a form that we can parse and write it to 4320 * nationalNumber if it is written in RFC3966; otherwise extract a possible 4321 * number out of it and write to nationalNumber. 4322 * 4323 * @param {?string} numberToParse number that we are attempting to parse. This 4324 * can contain formatting such as +, ( and -, as well as a phone number 4325 * extension. 4326 * @param {!goog.string.StringBuffer} nationalNumber a string buffer for storing 4327 * the national significant number. 4328 * @private 4329 */ 4330i18n.phonenumbers.PhoneNumberUtil.prototype.buildNationalNumberForParsing_ = 4331 function(numberToParse, nationalNumber) { 4332 4333 /** @type {number} */ 4334 var indexOfPhoneContext = numberToParse.indexOf( 4335 i18n.phonenumbers.PhoneNumberUtil.RFC3966_PHONE_CONTEXT_); 4336 if (indexOfPhoneContext >= 0) { 4337 var phoneContextStart = indexOfPhoneContext + 4338 i18n.phonenumbers.PhoneNumberUtil.RFC3966_PHONE_CONTEXT_.length; 4339 // If the phone context contains a phone number prefix, we need to capture 4340 // it, whereas domains will be ignored. 4341 // No length check is necessary, as per C++ or Java, since out-of-bounds 4342 // requests to charAt return an empty string. 4343 if (numberToParse.charAt(phoneContextStart) == 4344 i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) { 4345 // Additional parameters might follow the phone context. If so, we will 4346 // remove them here because the parameters after phone context are not 4347 // important for parsing the phone number. 4348 var phoneContextEnd = numberToParse.indexOf(';', phoneContextStart); 4349 if (phoneContextEnd > 0) { 4350 nationalNumber.append(numberToParse.substring(phoneContextStart, 4351 phoneContextEnd)); 4352 } else { 4353 nationalNumber.append(numberToParse.substring(phoneContextStart)); 4354 } 4355 } 4356 4357 // Now append everything between the "tel:" prefix and the phone-context. 4358 // This should include the national number, an optional extension or 4359 // isdn-subaddress component. Note we also handle the case when "tel:" is 4360 // missing, as we have seen in some of the phone number inputs. 4361 // In that case, we append everything from the beginning. 4362 var indexOfRfc3966Prefix = numberToParse.indexOf( 4363 i18n.phonenumbers.PhoneNumberUtil.RFC3966_PREFIX_); 4364 var indexOfNationalNumber = (indexOfRfc3966Prefix >= 0) ? 4365 indexOfRfc3966Prefix + 4366 i18n.phonenumbers.PhoneNumberUtil.RFC3966_PREFIX_.length : 0; 4367 nationalNumber.append(numberToParse.substring(indexOfNationalNumber, 4368 indexOfPhoneContext)); 4369 } else { 4370 // Extract a possible number from the string passed in (this strips leading 4371 // characters that could not be the start of a phone number.) 4372 nationalNumber.append( 4373 i18n.phonenumbers.PhoneNumberUtil.extractPossibleNumber(numberToParse)); 4374 } 4375 4376 // Delete the isdn-subaddress and everything after it if it is present. 4377 // Note extension won't appear at the same time with isdn-subaddress 4378 // according to paragraph 5.3 of the RFC3966 spec, 4379 /** @type {string} */ 4380 var nationalNumberStr = nationalNumber.toString(); 4381 var indexOfIsdn = nationalNumberStr.indexOf( 4382 i18n.phonenumbers.PhoneNumberUtil.RFC3966_ISDN_SUBADDRESS_); 4383 if (indexOfIsdn > 0) { 4384 nationalNumber.clear(); 4385 nationalNumber.append(nationalNumberStr.substring(0, indexOfIsdn)); 4386 } 4387 // If both phone context and isdn-subaddress are absent but other 4388 // parameters are present, the parameters are left in nationalNumber. This 4389 // is because we are concerned about deleting content from a potential 4390 // number string when there is no strong evidence that the number is 4391 // actually written in RFC3966. 4392}; 4393 4394 4395/** 4396 * Returns a new phone number containing only the fields needed to uniquely 4397 * identify a phone number, rather than any fields that capture the context in 4398 * which the phone number was created. 4399 * These fields correspond to those set in parse() rather than 4400 * parseAndKeepRawInput(). 4401 * 4402 * @param {i18n.phonenumbers.PhoneNumber} numberIn number that we want to copy 4403 * fields from. 4404 * @return {!i18n.phonenumbers.PhoneNumber} number with core fields only. 4405 * @private 4406 */ 4407i18n.phonenumbers.PhoneNumberUtil.copyCoreFieldsOnly_ = function(numberIn) { 4408 /** @type {i18n.phonenumbers.PhoneNumber} */ 4409 var phoneNumber = new i18n.phonenumbers.PhoneNumber(); 4410 phoneNumber.setCountryCode(numberIn.getCountryCodeOrDefault()); 4411 phoneNumber.setNationalNumber(numberIn.getNationalNumberOrDefault()); 4412 if (numberIn.getExtensionOrDefault().length > 0) { 4413 phoneNumber.setExtension(numberIn.getExtensionOrDefault()); 4414 } 4415 if (numberIn.getItalianLeadingZero()) { 4416 phoneNumber.setItalianLeadingZero(true); 4417 // This field is only relevant if there are leading zeros at all. 4418 phoneNumber.setNumberOfLeadingZeros( 4419 numberIn.getNumberOfLeadingZerosOrDefault()); 4420 } 4421 return phoneNumber; 4422}; 4423 4424 4425/** 4426 * Takes two phone numbers and compares them for equality. 4427 * 4428 * <p>Returns EXACT_MATCH if the country_code, NSN, presence of a leading zero 4429 * for Italian numbers and any extension present are the same. Returns NSN_MATCH 4430 * if either or both has no region specified, and the NSNs and extensions are 4431 * the same. Returns SHORT_NSN_MATCH if either or both has no region specified, 4432 * or the region specified is the same, and one NSN could be a shorter version 4433 * of the other number. This includes the case where one has an extension 4434 * specified, and the other does not. Returns NO_MATCH otherwise. For example, 4435 * the numbers +1 345 657 1234 and 657 1234 are a SHORT_NSN_MATCH. The numbers 4436 * +1 345 657 1234 and 345 657 are a NO_MATCH. 4437 * 4438 * @param {i18n.phonenumbers.PhoneNumber|string} firstNumberIn first number to 4439 * compare. If it is a string it can contain formatting, and can have 4440 * country calling code specified with + at the start. 4441 * @param {i18n.phonenumbers.PhoneNumber|string} secondNumberIn second number to 4442 * compare. If it is a string it can contain formatting, and can have 4443 * country calling code specified with + at the start. 4444 * @return {i18n.phonenumbers.PhoneNumberUtil.MatchType} NOT_A_NUMBER, NO_MATCH, 4445 * SHORT_NSN_MATCH, NSN_MATCH or EXACT_MATCH depending on the level of 4446 * equality of the two numbers, described in the method definition. 4447 */ 4448i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberMatch = 4449 function(firstNumberIn, secondNumberIn) { 4450 4451 // If the input arguements are strings parse them to a proto buffer format. 4452 // Else make copies of the phone numbers so that the numbers passed in are not 4453 // edited. 4454 /** @type {i18n.phonenumbers.PhoneNumber} */ 4455 var firstNumber; 4456 /** @type {i18n.phonenumbers.PhoneNumber} */ 4457 var secondNumber; 4458 if (typeof firstNumberIn == 'string') { 4459 // First see if the first number has an implicit country calling code, by 4460 // attempting to parse it. 4461 try { 4462 firstNumber = this.parse( 4463 firstNumberIn, i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_); 4464 } catch (e) { 4465 if (e.message != i18n.phonenumbers.Error.INVALID_COUNTRY_CODE) { 4466 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER; 4467 } 4468 // The first number has no country calling code. EXACT_MATCH is no longer 4469 // possible. We parse it as if the region was the same as that for the 4470 // second number, and if EXACT_MATCH is returned, we replace this with 4471 // NSN_MATCH. 4472 if (typeof secondNumberIn != 'string') { 4473 /** @type {string} */ 4474 var secondNumberRegion = this.getRegionCodeForCountryCode( 4475 secondNumberIn.getCountryCodeOrDefault()); 4476 if (secondNumberRegion != 4477 i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_) { 4478 try { 4479 firstNumber = this.parse(firstNumberIn, secondNumberRegion); 4480 } catch (e2) { 4481 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER; 4482 } 4483 /** @type {i18n.phonenumbers.PhoneNumberUtil.MatchType} */ 4484 var match = this.isNumberMatch(firstNumber, secondNumberIn); 4485 if (match == 4486 i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH) { 4487 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NSN_MATCH; 4488 } 4489 return match; 4490 } 4491 } 4492 // If the second number is a string or doesn't have a valid country 4493 // calling code, we parse the first number without country calling code. 4494 try { 4495 firstNumber = this.parseHelper_(firstNumberIn, null, false, false); 4496 } catch (e2) { 4497 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER; 4498 } 4499 } 4500 } else { 4501 firstNumber = firstNumberIn.clone(); 4502 } 4503 if (typeof secondNumberIn == 'string') { 4504 try { 4505 secondNumber = this.parse( 4506 secondNumberIn, i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_); 4507 return this.isNumberMatch(firstNumberIn, secondNumber); 4508 } catch (e) { 4509 if (e.message != i18n.phonenumbers.Error.INVALID_COUNTRY_CODE) { 4510 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER; 4511 } 4512 return this.isNumberMatch(secondNumberIn, firstNumber); 4513 } 4514 } else { 4515 secondNumber = secondNumberIn.clone(); 4516 } 4517 var firstNumberToCompare = 4518 i18n.phonenumbers.PhoneNumberUtil.copyCoreFieldsOnly_(firstNumber); 4519 var secondNumberToCompare = 4520 i18n.phonenumbers.PhoneNumberUtil.copyCoreFieldsOnly_(secondNumber); 4521 4522 // Early exit if both had extensions and these are different. 4523 if (firstNumberToCompare.hasExtension() && 4524 secondNumberToCompare.hasExtension() && 4525 firstNumberToCompare.getExtension() != 4526 secondNumberToCompare.getExtension()) { 4527 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH; 4528 } 4529 /** @type {number} */ 4530 var firstNumberCountryCode = firstNumberToCompare.getCountryCodeOrDefault(); 4531 /** @type {number} */ 4532 var secondNumberCountryCode = secondNumberToCompare.getCountryCodeOrDefault(); 4533 // Both had country_code specified. 4534 if (firstNumberCountryCode != 0 && secondNumberCountryCode != 0) { 4535 if (firstNumberToCompare.equals(secondNumberToCompare)) { 4536 return i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH; 4537 } else if (firstNumberCountryCode == secondNumberCountryCode && 4538 this.isNationalNumberSuffixOfTheOther_( 4539 firstNumberToCompare, secondNumberToCompare)) { 4540 // A SHORT_NSN_MATCH occurs if there is a difference because of the 4541 // presence or absence of an 'Italian leading zero', the presence or 4542 // absence of an extension, or one NSN being a shorter variant of the 4543 // other. 4544 return i18n.phonenumbers.PhoneNumberUtil.MatchType.SHORT_NSN_MATCH; 4545 } 4546 // This is not a match. 4547 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH; 4548 } 4549 // Checks cases where one or both country_code fields were not specified. To 4550 // make equality checks easier, we first set the country_code fields to be 4551 // equal. 4552 firstNumberToCompare.setCountryCode(0); 4553 secondNumberToCompare.setCountryCode(0); 4554 // If all else was the same, then this is an NSN_MATCH. 4555 if (firstNumberToCompare.equals(secondNumberToCompare)) { 4556 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NSN_MATCH; 4557 } 4558 if (this.isNationalNumberSuffixOfTheOther_(firstNumberToCompare, 4559 secondNumberToCompare)) { 4560 return i18n.phonenumbers.PhoneNumberUtil.MatchType.SHORT_NSN_MATCH; 4561 } 4562 return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH; 4563}; 4564 4565 4566/** 4567 * Returns true when one national number is the suffix of the other or both are 4568 * the same. 4569 * 4570 * @param {i18n.phonenumbers.PhoneNumber} firstNumber the first PhoneNumber 4571 * object. 4572 * @param {i18n.phonenumbers.PhoneNumber} secondNumber the second PhoneNumber 4573 * object. 4574 * @return {boolean} true if one PhoneNumber is the suffix of the other one. 4575 * @private 4576 */ 4577i18n.phonenumbers.PhoneNumberUtil.prototype.isNationalNumberSuffixOfTheOther_ = 4578 function(firstNumber, secondNumber) { 4579 4580 /** @type {string} */ 4581 var firstNumberNationalNumber = '' + firstNumber.getNationalNumber(); 4582 /** @type {string} */ 4583 var secondNumberNationalNumber = '' + secondNumber.getNationalNumber(); 4584 // Note that endsWith returns true if the numbers are equal. 4585 return goog.string.endsWith(firstNumberNationalNumber, 4586 secondNumberNationalNumber) || 4587 goog.string.endsWith(secondNumberNationalNumber, 4588 firstNumberNationalNumber); 4589}; 4590 4591 4592/** 4593 * Returns true if the number can be dialled from outside the region, or 4594 * unknown. If the number can only be dialled from within the region, returns 4595 * false. Does not check the number is a valid number. Note that, at the 4596 * moment, this method does not handle short numbers (which are currently 4597 * all presumed to not be diallable from outside their country). 4598 * 4599 * @param {i18n.phonenumbers.PhoneNumber} number the phone-number for which we 4600 * want to know whether it is diallable from outside the region. 4601 * @return {boolean} true if the number can only be dialled from within the 4602 * country. 4603 */ 4604i18n.phonenumbers.PhoneNumberUtil.prototype.canBeInternationallyDialled = 4605 function(number) { 4606 /** @type {i18n.phonenumbers.PhoneMetadata} */ 4607 var metadata = this.getMetadataForRegion(this.getRegionCodeForNumber(number)); 4608 if (metadata == null) { 4609 // Note numbers belonging to non-geographical entities (e.g. +800 numbers) 4610 // are always internationally diallable, and will be caught here. 4611 return true; 4612 } 4613 /** @type {string} */ 4614 var nationalSignificantNumber = this.getNationalSignificantNumber(number); 4615 return !this.isNumberMatchingDesc_(nationalSignificantNumber, 4616 metadata.getNoInternationalDialling()); 4617}; 4618 4619 4620/** 4621 * Check whether the entire input sequence can be matched against the regular 4622 * expression. 4623 * 4624 * @param {!RegExp|string} regex the regular expression to match against. 4625 * @param {string} str the string to test. 4626 * @return {boolean} true if str can be matched entirely against regex. 4627 * @package 4628 */ 4629i18n.phonenumbers.PhoneNumberUtil.matchesEntirely = function(regex, str) { 4630 /** @type {Array.<string>} */ 4631 var matchedGroups = (typeof regex == 'string') ? 4632 str.match('^(?:' + regex + ')$') : str.match(regex); 4633 if (matchedGroups && matchedGroups[0].length == str.length) { 4634 return true; 4635 } 4636 return false; 4637}; 4638 4639 4640/** 4641 * Check whether the input sequence can be prefix-matched against the regular 4642 * expression. 4643 * 4644 * @param {!RegExp|string} regex the regular expression to match against. 4645 * @param {string} str the string to test 4646 * @return {boolean} true if a prefix of the string can be matched with this 4647 * regex. 4648 * @package 4649 */ 4650i18n.phonenumbers.PhoneNumberUtil.matchesPrefix = function(regex, str) { 4651 /** @type {Array.<string>} */ 4652 var matchedGroups = (typeof regex == 'string') ? 4653 str.match('^(?:' + regex + ')') : str.match(regex); 4654 if (matchedGroups && goog.string.startsWith(str, matchedGroups[0])) { 4655 return true; 4656 } 4657 return false; 4658}; 4659