Browse Source

Update JS project to Java project revision 46. Patch submitted by tronikos.

pull/567/head
Shaopeng Jia 16 years ago
committed by Mihaela Rosca
parent
commit
174ec05c9f
10 changed files with 5936 additions and 1101 deletions
  1. +10
    -6
      javascript/README
  2. +295
    -195
      javascript/i18n/phonenumbers/asyoutypeformatter.js
  3. +201
    -106
      javascript/i18n/phonenumbers/asyoutypeformatter_test.js
  4. +26
    -2
      javascript/i18n/phonenumbers/demo.html
  5. +1205
    -532
      javascript/i18n/phonenumbers/metadata.js
  6. +175
    -64
      javascript/i18n/phonenumbers/metadatafortesting.js
  7. +3615
    -0
      javascript/i18n/phonenumbers/metadatalite.js
  8. +29
    -17
      javascript/i18n/phonenumbers/phonemetadata.pb.js
  9. +262
    -159
      javascript/i18n/phonenumbers/phonenumberutil.js
  10. +118
    -20
      javascript/i18n/phonenumbers/phonenumberutil_test.js

+ 10
- 6
javascript/README View File

@ -25,7 +25,7 @@ pages with your web browser:
How to update:
==============
The JavaScript library is ported from the Java implementation (revision 39).
The JavaScript library is ported from the Java implementation (revision 46).
When the Java project gets updated follow these steps to update the JavaScript
project:
@ -37,7 +37,7 @@ project:
i18n.phonenumbers.PhoneNumberDesc.prototype.exactlySameAs(other)
i18n.phonenumbers.PhoneNumber.prototype.exactlySameAs(other)
c. Manually update the toJsArray() Java methods in
/java/resources/com/google/i18n/phonenumbers/BuildMetadataJSON.java
/java/resources/com/google/i18n/phonenumbers/BuildMetadataJsonFromXml.java
2. If the phone number metadata in the XML format has changed
(java/resources/com/google/i18n/phonenumbers/src/PhoneNumberMetaData.xml)
@ -46,13 +46,17 @@ project:
ant -f java/build.xml
java -cp java/build/classes \
com.google.i18n.phonenumbers.BuildMetadataProtoFromXml \
com.google.i18n.phonenumbers.BuildMetadataJsonFromXml \
java/resources/com/google/i18n/phonenumbers/src/PhoneNumberMetaData.xml \
javascript/i18n/phonenumbers/metadata.js false json
javascript/i18n/phonenumbers/metadata.js false
java -cp java/build/classes \
com.google.i18n.phonenumbers.BuildMetadataProtoFromXml \
com.google.i18n.phonenumbers.BuildMetadataJsonFromXml \
java/resources/com/google/i18n/phonenumbers/src/PhoneNumberMetaData.xml \
javascript/i18n/phonenumbers/metadatalite.js true
java -cp java/build/classes \
com.google.i18n.phonenumbers.BuildMetadataJsonFromXml \
java/resources/com/google/i18n/phonenumbers/test/PhoneNumberMetaDataForTesting.xml \
javascript/i18n/phonenumbers/metadatafortesting.js false json
javascript/i18n/phonenumbers/metadatafortesting.js false
3. Manually port any changes of the Java code to the JavaScript code:
PhoneNumberUtil.java => phonenumberutil.js


+ 295
- 195
javascript/i18n/phonenumbers/asyoutypeformatter.js View File

@ -51,23 +51,38 @@ goog.require('i18n.phonenumbers.metadata');
*/
i18n.phonenumbers.AsYouTypeFormatter = function(regionCode) {
/**
* @type {boolean}
* A pattern that is used to match character classes in regular expressions.
* An example of a character class is [1-4].
* @const
* @type {RegExp}
* @private
*/
this.ableToFormat_ = true;
this.CHARACTER_CLASS_PATTERN_ = /\[([^\[\]])*\]/g;
/**
* @type {boolean}
* Any digit in a regular expression that actually denotes a digit. For
* example, in the regular expression 80[0-2]\d{6,10}, the first 2 digits
* (8 and 0) are standalone digits, but the rest are not.
* Two look-aheads are needed because the number following \\d could be a
* two-digit number, since the phone number can be as long as 15 digits.
* @const
* @type {RegExp}
* @private
*/
this.isInternationalFormatting_ = false;
this.STANDALONE_DIGIT_PATTERN_ = /\d(?=[^,}][^,}])/g;
/**
* @type {i18n.phonenumbers.PhoneNumberUtil}
* This is the minimum length of national number accrued that is required to
* trigger the formatter. The first element of the leadingDigitsPattern of
* each numberFormat contains a regular expression that matches up to this
* number of digits.
* @const
* @type {number}
* @private
*/
this.phoneUtil_ = i18n.phonenumbers.PhoneNumberUtil.getInstance();
// The digits that have not been entered yet will be represented by a \u2008,
// the punctuation space.
this.MIN_LEADING_DIGITS_LENGTH_ = 3;
/**
* The digits that have not been entered yet will be represented by a \u2008,
* the punctuation space.
* @const
* @type {string}
* @private
*/
@ -77,58 +92,75 @@ i18n.phonenumbers.AsYouTypeFormatter = function(regionCode) {
* @private
*/
this.digitPattern_ = new RegExp(this.digitPlaceholder_);
/**
* @type {number}
* @type {string}
* @private
*/
this.lastMatchPosition_ = 0;
this.currentOutput_ = '';
/**
* The position of a digit upon which inputDigitAndRememberPosition is most
* recently invoked, as found in the current output.
* @type {number}
* @type {!goog.string.StringBuffer}
* @private
*/
this.positionRemembered_ = 0;
this.formattingTemplate_ = new goog.string.StringBuffer();
/**
* The position of a digit upon which inputDigitAndRememberPosition is most
* recently invoked, as found in the original sequence of characters the user
* entered.
* @type {number}
* The pattern from numberFormat that is currently used to create
* formattingTemplate.
* @type {string}
* @private
*/
this.originalPosition_ = 0;
this.currentFormattingPattern_ = '';
/**
* A pattern that is used to match character classes in regular expressions.
* An example of a character class is [1-4].
* @type {RegExp}
* @type {!goog.string.StringBuffer}
* @private
*/
this.CHARACTER_CLASS_PATTERN_ = /\[([^\[\]])*\]/g;
this.accruedInput_ = new goog.string.StringBuffer();
/**
* Any digit in a regular expression that actually denotes a digit. For
* example, in the regular expression 80[0-2]\d{6,10}, the first 2 digits
* (8 and 0) are standalone digits, but the rest are not.
* Two look-aheads are needed because the number following \\d could be a
* two-digit number, since the phone number can be as long as 15 digits.
* @type {RegExp}
* @type {!goog.string.StringBuffer}
* @private
*/
this.STANDALONE_DIGIT_PATTERN_ = /\d(?=[^,}][^,}])/g;
this.accruedInputWithoutFormatting_ = new goog.string.StringBuffer();
/**
* @type {!goog.string.StringBuffer}
* @type {boolean}
* @private
*/
this.accruedInput_ = new goog.string.StringBuffer();
this.ableToFormat_ = true;
/**
* @type {!goog.string.StringBuffer}
* @type {boolean}
* @private
*/
this.accruedInputWithoutFormatting_ = new goog.string.StringBuffer();
this.isInternationalFormatting_ = false;
/**
* @type {!goog.string.StringBuffer}
* @type {boolean}
* @private
*/
this.currentOutput_ = new goog.string.StringBuffer();
this.isExpectingCountryCode_ = false;
/**
* @type {i18n.phonenumbers.PhoneNumberUtil}
* @private
*/
this.phoneUtil_ = i18n.phonenumbers.PhoneNumberUtil.getInstance();
/**
* @type {number}
* @private
*/
this.lastMatchPosition_ = 0;
/**
* The position of a digit upon which inputDigitAndRememberPosition is most
* recently invoked, as found in the original sequence of characters the user
* entered.
* @type {number}
* @private
*/
this.originalPosition_ = 0;
/**
* The position of a digit upon which inputDigitAndRememberPosition is most
* recently invoked, as found in accruedInputWithoutFormatting.
* entered.
* @type {number}
* @private
*/
this.positionToRemember_ = 0;
/**
* @type {!goog.string.StringBuffer}
* @private
@ -139,6 +171,12 @@ i18n.phonenumbers.AsYouTypeFormatter = function(regionCode) {
* @private
*/
this.nationalNumber_ = new goog.string.StringBuffer();
/**
* @type {Array.<i18n.phonenumbers.NumberFormat>}
* @private
*/
this.possibleFormats_ = [];
/**
* @type {string}
* @private
@ -170,61 +208,82 @@ i18n.phonenumbers.AsYouTypeFormatter.prototype.initializeCountrySpecificInfo_ =
};
/**
* @param {string} leadingFourDigitsOfNationalNumber
* @return {boolean} true if a new template is created as opposed to reusing the
* existing template.
* @private
*/
i18n.phonenumbers.AsYouTypeFormatter.prototype.chooseFormatAndCreateTemplate_ =
function(leadingFourDigitsOfNationalNumber) {
i18n.phonenumbers.AsYouTypeFormatter.prototype.maybeCreateNewTemplate_ =
function() {
/** @type {Array.<i18n.phonenumbers.NumberFormat>} */
var formatList = this.getAvailableFormats_(leadingFourDigitsOfNationalNumber);
if (formatList.length < 1) {
this.ableToFormat_ = false;
} else {
// When there are multiple available formats, the formatter uses the first
// format.
// When there are multiple available formats, the formatter uses the first
// format where a formatting template could be created.
/** @type {number} */
var possibleFormatsLength = this.possibleFormats_.length;
for (var i = 0; i < possibleFormatsLength; ++i) {
/** @type {i18n.phonenumbers.NumberFormat} */
var format = formatList[0];
if (!this.createFormattingTemplate_(format)) {
this.ableToFormat_ = false;
} else {
this.currentOutput_ =
new goog.string.StringBuffer(this.formattingTemplate_);
var numberFormat = this.possibleFormats_[i];
/** @type {string} */
var pattern = numberFormat.getPatternOrDefault();
if (this.currentFormattingPattern_ == pattern) {
return false;
}
if (this.createFormattingTemplate_(numberFormat)) {
this.currentFormattingPattern_ = pattern;
return true;
}
}
this.ableToFormat_ = false;
return false;
};
/**
* @param {string} leadingFourDigits
* @return {Array.<i18n.phonenumbers.NumberFormat>}
* @param {string} leadingThreeDigits
* @private
*/
i18n.phonenumbers.AsYouTypeFormatter.prototype.getAvailableFormats_ =
function(leadingFourDigits) {
function(leadingThreeDigits) {
/** @type {Array.<i18n.phonenumbers.NumberFormat>} */
var matchedList = [];
/** @type {Array.<i18n.phonenumbers.NumberFormat>} */
var formatList = (this.isInternationalFormatting_ && this.currentMetaData_
.intlNumberFormatCount() > 0) ? this.currentMetaData_
.intlNumberFormatArray() : this.currentMetaData_.numberFormatArray();
this.possibleFormats_ = formatList;
this.narrowDownPossibleFormats_(leadingThreeDigits);
};
/**
* @param {string} leadingDigits
* @private
*/
i18n.phonenumbers.AsYouTypeFormatter.prototype.narrowDownPossibleFormats_ =
function(leadingDigits) {
/** @type {Array.<i18n.phonenumbers.NumberFormat>} */
var possibleFormats = [];
/** @type {number} */
var lengthOfLeadingDigits = leadingDigits.length;
/** @type {number} */
var formatListLength = formatList.length;
for (var i = 0; i < formatListLength; ++i) {
var indexOfLeadingDigitsPattern =
lengthOfLeadingDigits - this.MIN_LEADING_DIGITS_LENGTH_;
/** @type {number} */
var possibleFormatsLength = this.possibleFormats_.length;
for (var i = 0; i < possibleFormatsLength; ++i) {
/** @type {i18n.phonenumbers.NumberFormat} */
var format = formatList[i];
if (format.hasLeadingDigits()) {
var format = this.possibleFormats_[i];
if (format.leadingDigitsPatternCount() > indexOfLeadingDigitsPattern) {
/** @type {RegExp} */
var leadingDigitsPattern =
new RegExp('^(' + format.getLeadingDigits() + ')');
if (leadingDigitsPattern.test(leadingFourDigits)) {
matchedList.push(format);
var leadingDigitsPattern = new RegExp('^(' +
format.getLeadingDigitsPattern(indexOfLeadingDigitsPattern) + ')');
if (leadingDigitsPattern.test(leadingDigits)) {
possibleFormats.push(this.possibleFormats_[i]);
}
} else {
matchedList.push(format);
// else the particular format has no more specific leadingDigitsPattern,
// and it should be retained.
possibleFormats.push(this.possibleFormats_[i]);
}
}
return matchedList;
this.possibleFormats_ = possibleFormats;
};
/**
@ -251,9 +310,9 @@ i18n.phonenumbers.AsYouTypeFormatter.prototype.createFormattingTemplate_ =
// Replace any standalone digit (not the one in d{}) with \d
numberPattern = numberPattern.replace(this.STANDALONE_DIGIT_PATTERN_, '\\d');
this.formattingTemplate_ = this.getFormattingTemplate_(numberPattern,
numberFormat);
this.formattingTemplate_.clear();
this.formattingTemplate_.append(this.getFormattingTemplate_(numberPattern,
numberFormat));
return true;
};
@ -291,16 +350,20 @@ i18n.phonenumbers.AsYouTypeFormatter.prototype.getFormattingTemplate_ =
* Clears the internal state of the formatter, so it could be reused.
*/
i18n.phonenumbers.AsYouTypeFormatter.prototype.clear = function() {
this.currentOutput_ = '';
this.accruedInput_.clear();
this.accruedInputWithoutFormatting_.clear();
this.currentOutput_.clear();
this.formattingTemplate_.clear();
this.lastMatchPosition_ = 0;
this.currentFormattingPattern_ = '';
this.prefixBeforeNationalNumber_.clear();
this.nationalNumber_.clear();
this.ableToFormat_ = true;
this.positionRemembered_ = 0;
this.positionToRemember_ = 0;
this.originalPosition_ = 0;
this.isInternationalFormatting_ = false;
this.isExpectingCountryCode_ = false;
this.possibleFormats_ = [];
if (this.currentMetaData_ != this.defaultMetaData_) {
this.initializeCountrySpecificInfo_(this.defaultCountry_);
}
@ -314,7 +377,9 @@ i18n.phonenumbers.AsYouTypeFormatter.prototype.clear = function() {
* @return {string} the partially formatted phone number.
*/
i18n.phonenumbers.AsYouTypeFormatter.prototype.inputDigit = function(nextChar) {
return this.inputDigitWithOptionToRememberPosition_(nextChar, false);
this.currentOutput_ =
this.inputDigitWithOptionToRememberPosition_(nextChar, false);
return this.currentOutput_;
};
/**
@ -329,13 +394,16 @@ i18n.phonenumbers.AsYouTypeFormatter.prototype.inputDigit = function(nextChar) {
i18n.phonenumbers.AsYouTypeFormatter.prototype.inputDigitAndRememberPosition =
function(nextChar) {
return this.inputDigitWithOptionToRememberPosition_(nextChar, true);
this.currentOutput_ =
this.inputDigitWithOptionToRememberPosition_(nextChar, true);
return this.currentOutput_;
};
/**
* @param {string} nextChar
* @param {boolean} rememberPosition
* @return {string}
* @private
*/
i18n.phonenumbers.AsYouTypeFormatter.prototype.
inputDigitWithOptionToRememberPosition_ = function(nextChar,
@ -343,8 +411,7 @@ i18n.phonenumbers.AsYouTypeFormatter.prototype.
this.accruedInput_.append(nextChar);
if (rememberPosition) {
this.positionRemembered_ = this.accruedInput_.getLength();
this.originalPosition_ = this.positionRemembered_;
this.originalPosition_ = this.accruedInput_.getLength();
}
// We do formatting on-the-fly only when each character entered is either a
// plus sign or a digit.
@ -353,53 +420,97 @@ i18n.phonenumbers.AsYouTypeFormatter.prototype.
this.ableToFormat_ = false;
}
if (!this.ableToFormat_) {
this.resetPositionOnFailureToFormat_();
return this.accruedInput_.toString();
}
nextChar = this.normalizeAndAccrueDigitsAndPlusSign_(nextChar);
nextChar = this.normalizeAndAccrueDigitsAndPlusSign_(nextChar,
rememberPosition);
// We start to attempt to format only when at least 6 digits (the plus sign is
// counted as a digit as well for this purpose) have been entered.
// We start to attempt to format only when at least MIN_LEADING_DIGITS_LENGTH
// digits (the plus sign is counted as a digit as well for this purpose) have
// been entered.
switch (this.accruedInputWithoutFormatting_.getLength()) {
case 0: // this is the case where the first few inputs are neither digits nor
// the plus sign.
case 1:
case 2:
return this.accruedInput_.toString();
case 3:
if (this.attemptToExtractIdd_()) {
this.isExpectingCountryCode_ = true;
} else {
// No IDD or plus sign is found, must be entering in national format.
this.removeNationalPrefixFromNationalNumber_();
return this.attemptToChooseFormattingPattern_();
}
case 4:
case 5:
return this.accruedInput_.toString();
if (this.isExpectingCountryCode_) {
if (this.attemptToExtractCountryCode_()) {
this.isExpectingCountryCode_ = false;
}
return this.prefixBeforeNationalNumber_.toString() +
this.nationalNumber_.toString();
}
// We make a last attempt to extract a country code at the 6th digit because
// the maximum length of IDD and country code are both 3.
case 6:
if (!this.extractIddAndValidCountryCode_()) {
if (this.isExpectingCountryCode_ && !this.attemptToExtractCountryCode_()) {
this.ableToFormat_ = false;
return this.accruedInput_.toString();
}
this.removeNationalPrefixFromNationalNumber_();
return this.attemptToChooseFormattingPattern_(rememberPosition);
default:
if (this.nationalNumber_.getLength() > 4) {
if (this.possibleFormats_.length > 0) {
// The formatting pattern is already chosen.
/** @type {string} */
var temp = this.inputDigitHelper_(nextChar, rememberPosition);
var tempNationalNumber = this.inputDigitHelper_(nextChar);
// See if the accrued digits can be formatted properly already. If not,
// use the results from inputDigitHelper, which does formatting based on
// the formatting pattern chosen.
/** @type {string} */
var formattedNumber = this.attemptToFormatAccruedDigits_();
if (formattedNumber.length > 0) {
return formattedNumber;
}
this.narrowDownPossibleFormats_(this.nationalNumber_.toString());
if (this.maybeCreateNewTemplate_()) {
return this.inputAccruedNationalNumber_();
}
return this.ableToFormat_ ?
this.prefixBeforeNationalNumber_.toString() + temp : temp;
this.prefixBeforeNationalNumber_.toString() + tempNationalNumber :
tempNationalNumber;
} else {
return this.attemptToChooseFormattingPattern_(rememberPosition);
return this.attemptToChooseFormattingPattern_();
}
}
};
/**
* @return {string}
* @private
*/
i18n.phonenumbers.AsYouTypeFormatter.prototype.resetPositionOnFailureToFormat_ =
i18n.phonenumbers.AsYouTypeFormatter.prototype.attemptToFormatAccruedDigits_ =
function() {
if (this.positionRemembered_ > 0) {
this.positionRemembered_ = this.originalPosition_;
this.currentOutput_.clear();
/** @type {string} */
var nationalNumber = this.nationalNumber_.toString();
/** @type {number} */
var possibleFormatsLength = this.possibleFormats_.length;
for (var i = 0; i < possibleFormatsLength; ++i) {
/** @type {i18n.phonenumbers.NumberFormat} */
var numFormat = this.possibleFormats_[i];
/** @type {string} */
var pattern = numFormat.getPatternOrDefault();
/** @type {RegExp} */
var patternRegExp = new RegExp('^(' + pattern + ')$');
if (patternRegExp.test(nationalNumber)) {
/** @type {string} */
var formattedNumber = nationalNumber.replace(new RegExp(pattern, 'g'),
numFormat.getFormat());
return this.prefixBeforeNationalNumber_.toString() + formattedNumber;
}
}
return '';
};
/**
@ -412,36 +523,51 @@ i18n.phonenumbers.AsYouTypeFormatter.prototype.resetPositionOnFailureToFormat_ =
i18n.phonenumbers.AsYouTypeFormatter.prototype.getRememberedPosition =
function() {
return this.positionRemembered_;
if (!this.ableToFormat_) {
return this.originalPosition_;
}
/** @type {number} */
var accruedInputIndex = 0;
/** @type {number} */
var currentOutputIndex = 0;
/** @type {string} */
var accruedInputWithoutFormatting =
this.accruedInputWithoutFormatting_.toString();
/** @type {string} */
var currentOutput = this.currentOutput_.toString();
while (accruedInputIndex < this.positionToRemember_) {
if (accruedInputWithoutFormatting.charAt(accruedInputIndex) ==
currentOutput.charAt(currentOutputIndex)) {
accruedInputIndex++;
currentOutputIndex++;
} else {
currentOutputIndex++;
}
}
return currentOutputIndex;
};
/**
* Attempts to set the formatting template and returns a string which contains
* the formatted version of the digits entered so far.
*
* @param {boolean} rememberPosition
* @return {string}
* @private
*/
i18n.phonenumbers.AsYouTypeFormatter.prototype.
attemptToChooseFormattingPattern_ = function(rememberPosition) {
attemptToChooseFormattingPattern_ = function() {
/** @type {string} */
var nationalNumber = this.nationalNumber_.toString();
/** @type {number} */
var nationalNumberLength = nationalNumber.length;
// We start to attempt to format only when as least 4 digits of national
// number (excluding national prefix) have been entered.
if (nationalNumberLength >= 4) {
this.chooseFormatAndCreateTemplate_(nationalNumber.substring(0, 4));
return this.inputAccruedNationalNumber_(rememberPosition);
// We start to attempt to format only when as least MIN_LEADING_DIGITS_LENGTH
// digits of national number (excluding national prefix) have been entered.
if (nationalNumber.length >= this.MIN_LEADING_DIGITS_LENGTH_) {
this.getAvailableFormats_(
nationalNumber.substring(0, this.MIN_LEADING_DIGITS_LENGTH_));
this.maybeCreateNewTemplate_();
return this.inputAccruedNationalNumber_();
} else {
if (rememberPosition) {
this.positionRemembered_ =
this.prefixBeforeNationalNumber_.length() + nationalNumberLength;
}
return this.prefixBeforeNationalNumber_.toString() +
this.nationalNumber_.toString();
return this.prefixBeforeNationalNumber_.toString() + nationalNumber;
}
};
@ -449,42 +575,27 @@ i18n.phonenumbers.AsYouTypeFormatter.prototype.
* Invokes inputDigitHelper on each digit of the national number accrued, and
* returns a formatted string in the end.
*
* @param {boolean} rememberPosition
* @return {string}
* @private
*/
i18n.phonenumbers.AsYouTypeFormatter.prototype.inputAccruedNationalNumber_ =
function(rememberPosition) {
function() {
/** @type {string} */
var nationalNumber = this.nationalNumber_.toString();
/** @type {number} */
var lengthOfNationalNumber = this.nationalNumber_.getLength();
var lengthOfNationalNumber = nationalNumber.length;
if (lengthOfNationalNumber > 0) {
// The positionRemembered should be only adjusted once in the loop that
// follows.
/** @type {boolean} */
var positionAlreadyAdjusted = false;
/** @type {string} */
var tempNationalNumber = '';
for (var i = 0; i < lengthOfNationalNumber; i++) {
tempNationalNumber =
this.inputDigitHelper_(this.nationalNumber_.toString().charAt(i),
rememberPosition);
if (!positionAlreadyAdjusted &&
this.positionRemembered_ -
this.prefixBeforeNationalNumber_.getLength() == i + 1) {
this.positionRemembered_ =
this.prefixBeforeNationalNumber_.getLength() +
tempNationalNumber.length;
positionAlreadyAdjusted = true;
}
this.inputDigitHelper_(nationalNumber.charAt(i));
}
return this.ableToFormat_ ?
this.prefixBeforeNationalNumber_.toString() + tempNationalNumber :
tempNationalNumber;
} else {
if (rememberPosition) {
this.positionRemembered_ = this.prefixBeforeNationalNumber_.length();
}
return this.prefixBeforeNationalNumber_.toString();
}
};
@ -503,13 +614,7 @@ i18n.phonenumbers.AsYouTypeFormatter.prototype.
nationalNumber.charAt(0) == '1') {
startOfNationalNumber = 1;
this.prefixBeforeNationalNumber_.append('1 ');
// Since a space is inserted after the national prefix in this case, we
// increase the remembered position by 1 for anything that is after the
// national prefix.
if (this.positionRemembered_ >
this.prefixBeforeNationalNumber_.getLength() - 1) {
this.positionRemembered_++;
}
this.isInternationalFormatting_ = true;
} else if (this.currentMetaData_.hasNationalPrefix()) {
/** @type {Array.<string>} */
var m = nationalNumber.match(this.nationalPrefixForParsing_);
@ -524,70 +629,73 @@ i18n.phonenumbers.AsYouTypeFormatter.prototype.
};
/**
* Extracts IDD, plus sign and country code to prefixBeforeNationalNumber when
* they are available, and places the remaining input into nationalNumber.
* Extracts IDD and plus sign to prefixBeforeNationalNumber when they are
* available, and places the remaining input into nationalNumber.
*
* @return {boolean} false when accruedInputWithoutFormatting begins with the
* plus sign or valid IDD for defaultCountry, but the sequence of digits
* after that does not form a valid country code. It returns true for all
* other cases.
* @return {boolean} true when accruedInputWithoutFormatting begins with the
* plus sign or valid IDD for defaultCountry.
* @private
*/
i18n.phonenumbers.AsYouTypeFormatter.prototype.extractIddAndValidCountryCode_ =
i18n.phonenumbers.AsYouTypeFormatter.prototype.attemptToExtractIdd_ =
function() {
/** @type {string} */
var accruedInputWithoutFormatting =
this.accruedInputWithoutFormatting_.toString();
this.nationalNumber_.clear();
/** @type {Array.<string>} */
var m = accruedInputWithoutFormatting.match(this.internationalPrefix_);
if (m != null && m[0] != null && m[0].length > 0) {
this.isInternationalFormatting_ = true;
/** @type {number} */
var startOfCountryCode = m[0].length;
/** @type {!goog.string.StringBuffer} */
var numberIncludeCountryCode = new goog.string.StringBuffer(
this.nationalNumber_.clear();
this.nationalNumber_.append(
accruedInputWithoutFormatting.substring(startOfCountryCode));
this.prefixBeforeNationalNumber_.append(
accruedInputWithoutFormatting.substring(0, startOfCountryCode));
if (accruedInputWithoutFormatting.charAt(0) !=
i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
this.prefixBeforeNationalNumber_.append(' ');
}
return true;
}
return false;
};
/**
* Extracts country code from the beginning of nationalNumber to
* prefixBeforeNationalNumber when they are available, and places the remaining
* input into nationalNumber.
*
* @return {boolean} true when a valid country code can be found.
* @private
*/
i18n.phonenumbers.AsYouTypeFormatter.prototype.attemptToExtractCountryCode_ =
function() {
if (this.nationalNumber_.getLength() == 0) {
return false;
}
/** @type {!goog.string.StringBuffer} */
var numberWithoutCountryCode = new goog.string.StringBuffer();
/** @type {number} */
var countryCode = this.phoneUtil_.extractCountryCode(
numberIncludeCountryCode, this.nationalNumber_);
this.nationalNumber_, numberWithoutCountryCode);
if (countryCode == 0) {
return false;
} else {
this.nationalNumber_.clear();
this.nationalNumber_.append(numberWithoutCountryCode.toString());
/** @type {string} */
var newRegionCode =
this.phoneUtil_.getRegionCodeForCountryCode(countryCode);
if (newRegionCode != this.defaultCountry_) {
this.initializeCountrySpecificInfo_(newRegionCode);
}
this.prefixBeforeNationalNumber_.append(accruedInputWithoutFormatting
.substring(0, startOfCountryCode));
if (accruedInputWithoutFormatting.charAt(0) !=
i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
if (this.positionRemembered_ >
this.prefixBeforeNationalNumber_.getLength()) {
// Since a space will be inserted in front of the country code in this
// case, we increase the remembered position by 1.
this.positionRemembered_++;
}
this.prefixBeforeNationalNumber_.append(' ');
}
/** @type {string} */
var countryCodeString = '' + countryCode;
if (this.positionRemembered_ >
this.prefixBeforeNationalNumber_.getLength() +
countryCodeString.length) {
// Since a space will be inserted after the country code in this case,
// we increase the remembered position by 1.
this.positionRemembered_++;
}
this.prefixBeforeNationalNumber_.append(countryCodeString).append(' ');
}
} else {
this.nationalNumber_.clear();
this.nationalNumber_.append(accruedInputWithoutFormatting);
}
return true;
};
@ -599,59 +707,51 @@ i18n.phonenumbers.AsYouTypeFormatter.prototype.extractIddAndValidCountryCode_ =
* in non-ASCII format.
*
* @param {string} nextChar
* @param {boolean} rememberPosition
* @return {string}
* @private
*/
i18n.phonenumbers.AsYouTypeFormatter.prototype.
normalizeAndAccrueDigitsAndPlusSign_ = function(nextChar) {
normalizeAndAccrueDigitsAndPlusSign_ = function(nextChar,
rememberPosition) {
if (nextChar == i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
this.accruedInputWithoutFormatting_.append(nextChar);
}
if (nextChar in i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS) {
nextChar = i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS[nextChar];
this.accruedInputWithoutFormatting_.append(nextChar);
this.nationalNumber_.append(nextChar);
}
if (rememberPosition) {
this.positionToRemember_ = this.accruedInputWithoutFormatting_.getLength();
}
return nextChar;
};
/**
* @param {string} nextChar
* @param {boolean} rememberPosition
* @return {string}
* @private
*/
i18n.phonenumbers.AsYouTypeFormatter.prototype.inputDigitHelper_ =
function(nextChar, rememberPosition) {
if (!(nextChar in i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS)) {
return this.currentOutput_.toString();
}
function(nextChar) {
/** @type {string} */
var currentOutput = this.currentOutput_.toString();
/** @type {string} */
var currentOutput2 = currentOutput.substring(this.lastMatchPosition_);
/** @type {number} */
var digitPatternStart = currentOutput2.search(this.digitPattern_);
if (digitPatternStart >= 0) {
this.currentOutput_ = new goog.string.StringBuffer(
currentOutput.substring(0, this.lastMatchPosition_) +
currentOutput2.replace(this.digitPattern_, nextChar));
this.lastMatchPosition_ += digitPatternStart;
if (rememberPosition) {
this.positionRemembered_ = this.prefixBeforeNationalNumber_.getLength() +
this.lastMatchPosition_ + 1;
}
return this.currentOutput_.toString()
.substring(0, this.lastMatchPosition_ + 1);
var formattingTemplate = this.formattingTemplate_.toString();
if (formattingTemplate.substring(this.lastMatchPosition_)
.search(this.digitPattern_) >= 0) {
/** @type {number} */
var digitPatternStart = formattingTemplate.search(this.digitPattern_);
/** @type {string} */
var tempTemplate = formattingTemplate.replace(this.digitPattern_, nextChar);
this.formattingTemplate_.clear();
this.formattingTemplate_.append(tempTemplate);
this.lastMatchPosition_ = digitPatternStart;
return tempTemplate.substring(0, this.lastMatchPosition_ + 1);
} else {
// More digits are entered than we could handle.
this.currentOutput_.append(nextChar);
this.ableToFormat_ = false;
this.resetPositionOnFailureToFormat_();
return this.accruedInput_.toString();
}
};

+ 201
- 106
javascript/i18n/phonenumbers/asyoutypeformatter_test.js View File

@ -21,16 +21,17 @@
goog.require('goog.testing.jsunit');
goog.require('i18n.phonenumbers.AsYouTypeFormatter');
function testAsYouTypeFormatterUS() {
function testAYTFUS() {
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('US');
assertEquals('6', f.inputDigit('6'));
assertEquals('65', f.inputDigit('5'));
assertEquals('650', f.inputDigit('0'));
assertEquals('6502', f.inputDigit('2'));
assertEquals('65025', f.inputDigit('5'));
assertEquals('650 2', f.inputDigit('2'));
assertEquals('650 25', f.inputDigit('5'));
assertEquals('650 253', f.inputDigit('3'));
assertEquals('650 253 2', f.inputDigit('2'));
// Note this is how a US local number (without area code) should be formatted.
assertEquals('650 2532', f.inputDigit('2'));
assertEquals('650 253 22', f.inputDigit('2'));
assertEquals('650 253 222', f.inputDigit('2'));
assertEquals('650 253 2222', f.inputDigit('2'));
@ -38,9 +39,9 @@ function testAsYouTypeFormatterUS() {
f.clear();
assertEquals('1', f.inputDigit('1'));
assertEquals('16', f.inputDigit('6'));
assertEquals('165', f.inputDigit('5'));
assertEquals('1650', f.inputDigit('0'));
assertEquals('16502', f.inputDigit('2'));
assertEquals('1 65', f.inputDigit('5'));
assertEquals('1 650', f.inputDigit('0'));
assertEquals('1 650 2', f.inputDigit('2'));
assertEquals('1 650 25', f.inputDigit('5'));
assertEquals('1 650 253', f.inputDigit('3'));
assertEquals('1 650 253 2', f.inputDigit('2'));
@ -51,12 +52,12 @@ function testAsYouTypeFormatterUS() {
f.clear();
assertEquals('0', f.inputDigit('0'));
assertEquals('01', f.inputDigit('1'));
assertEquals('011', f.inputDigit('1'));
assertEquals('0114', f.inputDigit('4'));
assertEquals('01144', f.inputDigit('4'));
assertEquals('011 ', f.inputDigit('1'));
assertEquals('011 4', f.inputDigit('4'));
assertEquals('011 44 ', f.inputDigit('4'));
assertEquals('011 44 6', f.inputDigit('6'));
assertEquals('011 44 61', f.inputDigit('1'));
assertEquals('011 44 612', f.inputDigit('2'));
assertEquals('011 44 6 12', f.inputDigit('2'));
assertEquals('011 44 6 123', f.inputDigit('3'));
assertEquals('011 44 6 123 1', f.inputDigit('1'));
assertEquals('011 44 6 123 12', f.inputDigit('2'));
@ -68,12 +69,12 @@ function testAsYouTypeFormatterUS() {
f.clear();
assertEquals('0', f.inputDigit('0'));
assertEquals('01', f.inputDigit('1'));
assertEquals('011', f.inputDigit('1'));
assertEquals('0115', f.inputDigit('5'));
assertEquals('01154', f.inputDigit('4'));
assertEquals('011 ', f.inputDigit('1'));
assertEquals('011 5', f.inputDigit('5'));
assertEquals('011 54 ', f.inputDigit('4'));
assertEquals('011 54 9', f.inputDigit('9'));
assertEquals('011 54 91', f.inputDigit('1'));
assertEquals('011 54 911', f.inputDigit('1'));
assertEquals('011 54 9 11', f.inputDigit('1'));
assertEquals('011 54 9 11 2', f.inputDigit('2'));
assertEquals('011 54 9 11 23', f.inputDigit('3'));
assertEquals('011 54 9 11 231', f.inputDigit('1'));
@ -83,13 +84,30 @@ function testAsYouTypeFormatterUS() {
assertEquals('011 54 9 11 2312 123', f.inputDigit('3'));
assertEquals('011 54 9 11 2312 1234', f.inputDigit('4'));
f.clear();
assertEquals('0', f.inputDigit('0'));
assertEquals('01', f.inputDigit('1'));
assertEquals('011 ', f.inputDigit('1'));
assertEquals('011 2', f.inputDigit('2'));
assertEquals('011 24', f.inputDigit('4'));
assertEquals('011 244 ', f.inputDigit('4'));
assertEquals('011 244 2', f.inputDigit('2'));
assertEquals('011 244 28', f.inputDigit('8'));
assertEquals('011 244 280', f.inputDigit('0'));
assertEquals('011 244 280 0', f.inputDigit('0'));
assertEquals('011 244 280 00', f.inputDigit('0'));
assertEquals('011 244 280 000', f.inputDigit('0'));
assertEquals('011 244 280 000 0', f.inputDigit('0'));
assertEquals('011 244 280 000 00', f.inputDigit('0'));
assertEquals('011 244 280 000 000', f.inputDigit('0'));
f.clear();
assertEquals('+', f.inputDigit('+'));
assertEquals('+4', f.inputDigit('4'));
assertEquals('+48', f.inputDigit('8'));
assertEquals('+488', f.inputDigit('8'));
assertEquals('+4888', f.inputDigit('8'));
assertEquals('+48 881', f.inputDigit('1'));
assertEquals('+48 ', f.inputDigit('8'));
assertEquals('+48 8', f.inputDigit('8'));
assertEquals('+48 88', f.inputDigit('8'));
assertEquals('+48 88 1', f.inputDigit('1'));
assertEquals('+48 88 12', f.inputDigit('2'));
assertEquals('+48 88 123', f.inputDigit('3'));
assertEquals('+48 88 123 1', f.inputDigit('1'));
@ -98,22 +116,22 @@ function testAsYouTypeFormatterUS() {
assertEquals('+48 88 123 12 12', f.inputDigit('2'));
}
function testAsYouTypeFormatterUSFullWidthCharacters() {
function testAYTFUSFullWidthCharacters() {
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('US');
assertEquals('\uFF16', f.inputDigit('\uFF16'));
assertEquals('\uFF16\uFF15', f.inputDigit('\uFF15'));
assertEquals('\uFF16\uFF15\uFF10', f.inputDigit('\uFF10'));
assertEquals('\uFF16\uFF15\uFF10\uFF12', f.inputDigit('\uFF12'));
assertEquals('\uFF16\uFF15\uFF10\uFF12\uFF15', f.inputDigit('\uFF15'));
assertEquals('650', f.inputDigit('\uFF10'));
assertEquals('650 2', f.inputDigit('\uFF12'));
assertEquals('650 25', f.inputDigit('\uFF15'));
assertEquals('650 253', f.inputDigit('\uFF13'));
assertEquals('650 253 2', f.inputDigit('\uFF12'));
assertEquals('650 2532', f.inputDigit('\uFF12'));
assertEquals('650 253 22', f.inputDigit('\uFF12'));
assertEquals('650 253 222', f.inputDigit('\uFF12'));
assertEquals('650 253 2222', f.inputDigit('\uFF12'));
}
function testAsYouTypeFormatterUSMobileShortCode() {
function testAYTFUSMobileShortCode() {
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('US');
assertEquals('*', f.inputDigit('*'));
@ -123,7 +141,7 @@ function testAsYouTypeFormatterUSMobileShortCode() {
assertEquals('*121#', f.inputDigit('#'));
}
function testAsYouTypeFormatterUSVanityNumber() {
function testAYTFUSVanityNumber() {
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('US');
assertEquals('8', f.inputDigit('8'));
@ -140,17 +158,17 @@ function testAsYouTypeFormatterUSVanityNumber() {
assertEquals('800 MY APPLE', f.inputDigit('E'));
}
function testAsYouTypeFormatterAndRememberPositionUS() {
function testAYTFAndRememberPositionUS() {
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('US');
assertEquals('1', f.inputDigitAndRememberPosition('1'));
assertEquals(1, f.getRememberedPosition());
assertEquals('16', f.inputDigit('6'));
assertEquals('165', f.inputDigit('5'));
assertEquals('1 65', f.inputDigit('5'));
assertEquals(1, f.getRememberedPosition());
assertEquals('1650', f.inputDigitAndRememberPosition('0'));
assertEquals(4, f.getRememberedPosition());
assertEquals('16502', f.inputDigit('2'));
assertEquals('1 650', f.inputDigitAndRememberPosition('0'));
assertEquals(5, f.getRememberedPosition());
assertEquals('1 650 2', f.inputDigit('2'));
assertEquals('1 650 25', f.inputDigit('5'));
// Note the remembered position for digit '0' changes from 4 to 5, because a
// space is now inserted in the front.
@ -170,39 +188,40 @@ function testAsYouTypeFormatterAndRememberPositionUS() {
f.clear();
assertEquals('1', f.inputDigit('1'));
assertEquals('16', f.inputDigit('6'));
assertEquals('165', f.inputDigitAndRememberPosition('5'));
assertEquals('1650', f.inputDigit('0'));
assertEquals('16', f.inputDigitAndRememberPosition('6'));
assertEquals(2, f.getRememberedPosition());
assertEquals('1 65', f.inputDigit('5'));
assertEquals('1 650', f.inputDigit('0'));
assertEquals(3, f.getRememberedPosition());
assertEquals('16502', f.inputDigit('2'));
assertEquals('1 650 2', f.inputDigit('2'));
assertEquals('1 650 25', f.inputDigit('5'));
assertEquals(4, f.getRememberedPosition());
assertEquals(3, f.getRememberedPosition());
assertEquals('1 650 253', f.inputDigit('3'));
assertEquals('1 650 253 2', f.inputDigit('2'));
assertEquals('1 650 253 22', f.inputDigit('2'));
assertEquals(4, f.getRememberedPosition());
assertEquals(3, f.getRememberedPosition());
assertEquals('1 650 253 222', f.inputDigit('2'));
assertEquals('1 650 253 2222', f.inputDigit('2'));
assertEquals('165025322222', f.inputDigit('2'));
assertEquals(3, f.getRememberedPosition());
assertEquals(2, f.getRememberedPosition());
assertEquals('1650253222222', f.inputDigit('2'));
assertEquals(3, f.getRememberedPosition());
assertEquals(2, f.getRememberedPosition());
f.clear();
assertEquals('6', f.inputDigit('6'));
assertEquals('65', f.inputDigit('5'));
assertEquals('650', f.inputDigit('0'));
assertEquals('6502', f.inputDigit('2'));
assertEquals('65025', f.inputDigitAndRememberPosition('5'));
assertEquals(5, f.getRememberedPosition());
assertEquals('650 2', f.inputDigit('2'));
assertEquals('650 25', f.inputDigit('5'));
assertEquals('650 253', f.inputDigit('3'));
assertEquals(6, f.getRememberedPosition());
assertEquals('650 253 2', f.inputDigit('2'));
assertEquals('650 2532', f.inputDigitAndRememberPosition('2'));
assertEquals(8, f.getRememberedPosition());
assertEquals('650 253 22', f.inputDigit('2'));
assertEquals(9, f.getRememberedPosition());
assertEquals('650 253 222', f.inputDigit('2'));
// No more formatting when semicolon is entered.
assertEquals('650253222;', f.inputDigit(';'));
assertEquals(5, f.getRememberedPosition());
assertEquals(7, f.getRememberedPosition());
assertEquals('650253222;2', f.inputDigit('2'));
f.clear();
@ -226,14 +245,14 @@ function testAsYouTypeFormatterAndRememberPositionUS() {
f.clear();
assertEquals('0', f.inputDigit('0'));
assertEquals('01', f.inputDigit('1'));
assertEquals('011', f.inputDigit('1'));
assertEquals('0114', f.inputDigitAndRememberPosition('4'));
assertEquals('01148', f.inputDigit('8'));
assertEquals(4, f.getRememberedPosition());
assertEquals('011 ', f.inputDigit('1'));
assertEquals('011 4', f.inputDigitAndRememberPosition('4'));
assertEquals('011 48 ', f.inputDigit('8'));
assertEquals(5, f.getRememberedPosition());
assertEquals('011 48 8', f.inputDigit('8'));
assertEquals(5, f.getRememberedPosition());
assertEquals('011 48 88', f.inputDigit('8'));
assertEquals('011 48 881', f.inputDigit('1'));
assertEquals('011 48 88 1', f.inputDigit('1'));
assertEquals('011 48 88 12', f.inputDigit('2'));
assertEquals(5, f.getRememberedPosition());
assertEquals('011 48 88 123', f.inputDigit('3'));
@ -245,10 +264,10 @@ function testAsYouTypeFormatterAndRememberPositionUS() {
f.clear();
assertEquals('+', f.inputDigit('+'));
assertEquals('+1', f.inputDigit('1'));
assertEquals('+16', f.inputDigitAndRememberPosition('6'));
assertEquals('+165', f.inputDigit('5'));
assertEquals('+1650', f.inputDigit('0'));
assertEquals(3, f.getRememberedPosition());
assertEquals('+1 6', f.inputDigitAndRememberPosition('6'));
assertEquals('+1 65', f.inputDigit('5'));
assertEquals('+1 650', f.inputDigit('0'));
assertEquals(4, f.getRememberedPosition());
assertEquals('+1 650 2', f.inputDigit('2'));
assertEquals(4, f.getRememberedPosition());
assertEquals('+1 650 25', f.inputDigit('5'));
@ -261,10 +280,10 @@ function testAsYouTypeFormatterAndRememberPositionUS() {
f.clear();
assertEquals('+', f.inputDigit('+'));
assertEquals('+1', f.inputDigit('1'));
assertEquals('+16', f.inputDigitAndRememberPosition('6'));
assertEquals('+165', f.inputDigit('5'));
assertEquals('+1650', f.inputDigit('0'));
assertEquals(3, f.getRememberedPosition());
assertEquals('+1 6', f.inputDigitAndRememberPosition('6'));
assertEquals('+1 65', f.inputDigit('5'));
assertEquals('+1 650', f.inputDigit('0'));
assertEquals(4, f.getRememberedPosition());
assertEquals('+1 650 2', f.inputDigit('2'));
assertEquals(4, f.getRememberedPosition());
assertEquals('+1 650 25', f.inputDigit('5'));
@ -276,15 +295,15 @@ function testAsYouTypeFormatterAndRememberPositionUS() {
assertEquals(3, f.getRememberedPosition());
}
function testAsYouTypeFormatterGBFixedLine() {
function testAYTFGBFixedLine() {
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('GB');
assertEquals('0', f.inputDigit('0'));
assertEquals('02', f.inputDigit('2'));
assertEquals('020', f.inputDigit('0'));
assertEquals('0207', f.inputDigitAndRememberPosition('7'));
assertEquals(4, f.getRememberedPosition());
assertEquals('02070', f.inputDigit('0'));
assertEquals('020 7', f.inputDigitAndRememberPosition('7'));
assertEquals(5, f.getRememberedPosition());
assertEquals('020 70', f.inputDigit('0'));
assertEquals('020 703', f.inputDigit('3'));
assertEquals(5, f.getRememberedPosition());
assertEquals('020 7031', f.inputDigit('1'));
@ -294,14 +313,14 @@ function testAsYouTypeFormatterGBFixedLine() {
assertEquals('020 7031 3000', f.inputDigit('0'));
}
function testAsYouTypeFormatterGBTollFree() {
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
function testAYTFGBTollFree() {
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('gb');
assertEquals('0', f.inputDigit('0'));
assertEquals('08', f.inputDigit('8'));
assertEquals('080', f.inputDigit('0'));
assertEquals('0807', f.inputDigit('7'));
assertEquals('08070', f.inputDigit('0'));
assertEquals('080 7', f.inputDigit('7'));
assertEquals('080 70', f.inputDigit('0'));
assertEquals('080 703', f.inputDigit('3'));
assertEquals('080 7031', f.inputDigit('1'));
assertEquals('080 7031 3', f.inputDigit('3'));
@ -310,14 +329,14 @@ function testAsYouTypeFormatterGBTollFree() {
assertEquals('080 7031 3000', f.inputDigit('0'));
}
function testAsYouTypeFormatterGBPremiumRate() {
function testAYTFGBPremiumRate() {
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('GB');
assertEquals('0', f.inputDigit('0'));
assertEquals('09', f.inputDigit('9'));
assertEquals('090', f.inputDigit('0'));
assertEquals('0907', f.inputDigit('7'));
assertEquals('09070', f.inputDigit('0'));
assertEquals('090 7', f.inputDigit('7'));
assertEquals('090 70', f.inputDigit('0'));
assertEquals('090 703', f.inputDigit('3'));
assertEquals('090 7031', f.inputDigit('1'));
assertEquals('090 7031 3', f.inputDigit('3'));
@ -326,14 +345,14 @@ function testAsYouTypeFormatterGBPremiumRate() {
assertEquals('090 7031 3000', f.inputDigit('0'));
}
function testAsYouTypeFormatterNZMobile() {
function testAYTFNZMobile() {
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('NZ');
assertEquals('0', f.inputDigit('0'));
assertEquals('02', f.inputDigit('2'));
assertEquals('021', f.inputDigit('1'));
assertEquals('0211', f.inputDigit('1'));
assertEquals('02112', f.inputDigit('2'));
assertEquals('02-11', f.inputDigit('1'));
assertEquals('02-112', f.inputDigit('2'));
// Note the unittest is using fake metadata which might produce non-ideal
// results.
assertEquals('02-112 3', f.inputDigit('3'));
@ -342,26 +361,54 @@ function testAsYouTypeFormatterNZMobile() {
assertEquals('02-112 3456', f.inputDigit('6'));
}
function testAsYouTypeFormatterDE() {
function testAYTFDE() {
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('DE');
assertEquals('0', f.inputDigit('0'));
assertEquals('03', f.inputDigit('3'));
assertEquals('030', f.inputDigit('0'));
assertEquals('0301', f.inputDigit('1'));
assertEquals('03012', f.inputDigit('2'));
assertEquals('030 1', f.inputDigit('1'));
assertEquals('030 12', f.inputDigit('2'));
assertEquals('030 123', f.inputDigit('3'));
assertEquals('030 1234', f.inputDigit('4'));
// 08021 2345
f.clear();
assertEquals('0', f.inputDigit('0'));
assertEquals('08', f.inputDigit('8'));
assertEquals('080', f.inputDigit('0'));
assertEquals('0802', f.inputDigit('2'));
assertEquals('08021', f.inputDigit('1'));
assertEquals('08021 2', f.inputDigit('2'));
assertEquals('08021 23', f.inputDigit('3'));
assertEquals('08021 234', f.inputDigit('4'));
assertEquals('08021 2345', f.inputDigit('5'));
// 00 1 650 253 2250
f.clear();
assertEquals('0', f.inputDigit('0'));
assertEquals('00', f.inputDigit('0'));
assertEquals('00 1 ', f.inputDigit('1'));
assertEquals('00 1 6', f.inputDigit('6'));
assertEquals('00 1 65', f.inputDigit('5'));
assertEquals('00 1 650', f.inputDigit('0'));
assertEquals('00 1 650 2', f.inputDigit('2'));
assertEquals('00 1 650 25', f.inputDigit('5'));
assertEquals('00 1 650 253', f.inputDigit('3'));
assertEquals('00 1 650 253 2', f.inputDigit('2'));
assertEquals('00 1 650 253 22', f.inputDigit('2'));
assertEquals('00 1 650 253 222', f.inputDigit('2'));
assertEquals('00 1 650 253 2222', f.inputDigit('2'));
}
function testAsYouTypeFormatterAR() {
function testAYTFAR() {
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('AR');
assertEquals('0', f.inputDigit('0'));
assertEquals('01', f.inputDigit('1'));
assertEquals('011', f.inputDigit('1'));
assertEquals('0117', f.inputDigit('7'));
assertEquals('01170', f.inputDigit('0'));
assertEquals('011 7', f.inputDigit('7'));
assertEquals('011 70', f.inputDigit('0'));
assertEquals('011 703', f.inputDigit('3'));
assertEquals('011 7031', f.inputDigit('1'));
assertEquals('011 7031-3', f.inputDigit('3'));
@ -370,15 +417,15 @@ function testAsYouTypeFormatterAR() {
assertEquals('011 7031-3000', f.inputDigit('0'));
}
function testAsYouTypeFormatterARMobile() {
function testAYTFARMobile() {
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('AR');
assertEquals('+', f.inputDigit('+'));
assertEquals('+5', f.inputDigit('5'));
assertEquals('+54', f.inputDigit('4'));
assertEquals('+549', f.inputDigit('9'));
assertEquals('+5491', f.inputDigit('1'));
assertEquals('+54 911', f.inputDigit('1'));
assertEquals('+54 ', f.inputDigit('4'));
assertEquals('+54 9', f.inputDigit('9'));
assertEquals('+54 91', f.inputDigit('1'));
assertEquals('+54 9 11', f.inputDigit('1'));
assertEquals('+54 9 11 2', f.inputDigit('2'));
assertEquals('+54 9 11 23', f.inputDigit('3'));
assertEquals('+54 9 11 231', f.inputDigit('1'));
@ -389,16 +436,16 @@ function testAsYouTypeFormatterARMobile() {
assertEquals('+54 9 11 2312 1234', f.inputDigit('4'));
}
function testAsYouTypeFormatterKR() {
function testAYTFKR() {
// +82 51 234 5678
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('KR');
assertEquals('+', f.inputDigit('+'));
assertEquals('+8', f.inputDigit('8'));
assertEquals('+82', f.inputDigit('2'));
assertEquals('+825', f.inputDigit('5'));
assertEquals('+8251', f.inputDigit('1'));
assertEquals('+82 512', f.inputDigit('2'));
assertEquals('+82 ', f.inputDigit('2'));
assertEquals('+82 5', f.inputDigit('5'));
assertEquals('+82 51', f.inputDigit('1'));
assertEquals('+82 51-2', f.inputDigit('2'));
assertEquals('+82 51-23', f.inputDigit('3'));
assertEquals('+82 51-234', f.inputDigit('4'));
assertEquals('+82 51-234-5', f.inputDigit('5'));
@ -410,10 +457,10 @@ function testAsYouTypeFormatterKR() {
f.clear();
assertEquals('+', f.inputDigit('+'));
assertEquals('+8', f.inputDigit('8'));
assertEquals('+82', f.inputDigit('2'));
assertEquals('+822', f.inputDigit('2'));
assertEquals('+8225', f.inputDigit('5'));
assertEquals('+82 253', f.inputDigit('3'));
assertEquals('+82 ', f.inputDigit('2'));
assertEquals('+82 2', f.inputDigit('2'));
assertEquals('+82 25', f.inputDigit('5'));
assertEquals('+82 2-53', f.inputDigit('3'));
assertEquals('+82 2-531', f.inputDigit('1'));
assertEquals('+82 2-531-5', f.inputDigit('5'));
assertEquals('+82 2-531-56', f.inputDigit('6'));
@ -424,10 +471,10 @@ function testAsYouTypeFormatterKR() {
f.clear();
assertEquals('+', f.inputDigit('+'));
assertEquals('+8', f.inputDigit('8'));
assertEquals('+82', f.inputDigit('2'));
assertEquals('+822', f.inputDigit('2'));
assertEquals('+8223', f.inputDigit('3'));
assertEquals('+82 236', f.inputDigit('6'));
assertEquals('+82 ', f.inputDigit('2'));
assertEquals('+82 2', f.inputDigit('2'));
assertEquals('+82 23', f.inputDigit('3'));
assertEquals('+82 2-36', f.inputDigit('6'));
assertEquals('+82 2-366', f.inputDigit('6'));
assertEquals('+82 2-3665', f.inputDigit('5'));
assertEquals('+82 2-3665-5', f.inputDigit('5'));
@ -435,22 +482,21 @@ function testAsYouTypeFormatterKR() {
assertEquals('+82 2-3665-567', f.inputDigit('7'));
assertEquals('+82 2-3665-5678', f.inputDigit('8'));
// 02-114 : This is too short to format. Checking that there are no
// side-effects.
// 02-114
f.clear();
assertEquals('0', f.inputDigit('0'));
assertEquals('02', f.inputDigit('2'));
assertEquals('021', f.inputDigit('1'));
assertEquals('0211', f.inputDigit('1'));
assertEquals('02114', f.inputDigit('4'));
assertEquals('02-11', f.inputDigit('1'));
assertEquals('02-114', f.inputDigit('4'));
// 02-1300
f.clear();
assertEquals('0', f.inputDigit('0'));
assertEquals('02', f.inputDigit('2'));
assertEquals('021', f.inputDigit('1'));
assertEquals('0213', f.inputDigit('3'));
assertEquals('02130', f.inputDigit('0'));
assertEquals('02-13', f.inputDigit('3'));
assertEquals('02-130', f.inputDigit('0'));
assertEquals('02-1300', f.inputDigit('0'));
// 011-456-7890
@ -458,8 +504,8 @@ function testAsYouTypeFormatterKR() {
assertEquals('0', f.inputDigit('0'));
assertEquals('01', f.inputDigit('1'));
assertEquals('011', f.inputDigit('1'));
assertEquals('0114', f.inputDigit('4'));
assertEquals('01145', f.inputDigit('5'));
assertEquals('011-4', f.inputDigit('4'));
assertEquals('011-45', f.inputDigit('5'));
assertEquals('011-456', f.inputDigit('6'));
assertEquals('011-456-7', f.inputDigit('7'));
assertEquals('011-456-78', f.inputDigit('8'));
@ -471,8 +517,8 @@ function testAsYouTypeFormatterKR() {
assertEquals('0', f.inputDigit('0'));
assertEquals('01', f.inputDigit('1'));
assertEquals('011', f.inputDigit('1'));
assertEquals('0119', f.inputDigit('9'));
assertEquals('01198', f.inputDigit('8'));
assertEquals('011-9', f.inputDigit('9'));
assertEquals('011-98', f.inputDigit('8'));
assertEquals('011-987', f.inputDigit('7'));
assertEquals('011-9876', f.inputDigit('6'));
assertEquals('011-9876-7', f.inputDigit('7'));
@ -480,3 +526,52 @@ function testAsYouTypeFormatterKR() {
assertEquals('011-9876-789', f.inputDigit('9'));
assertEquals('011-9876-7890', f.inputDigit('0'));
}
function testAYTFMultipleLeadingDigitPatterns() {
// +81 50 2345 6789
/** @type {i18n.phonenumbers.AsYouTypeFormatter} */
var f = new i18n.phonenumbers.AsYouTypeFormatter('JP');
assertEquals('+', f.inputDigit('+'));
assertEquals('+8', f.inputDigit('8'));
assertEquals('+81 ', f.inputDigit('1'));
assertEquals('+81 5', f.inputDigit('5'));
assertEquals('+81 50', f.inputDigit('0'));
assertEquals('+81 50 2', f.inputDigit('2'));
assertEquals('+81 50 23', f.inputDigit('3'));
assertEquals('+81 50 234', f.inputDigit('4'));
assertEquals('+81 50 2345', f.inputDigit('5'));
assertEquals('+81 50 2345 6', f.inputDigit('6'));
assertEquals('+81 50 2345 67', f.inputDigit('7'));
assertEquals('+81 50 2345 678', f.inputDigit('8'));
assertEquals('+81 50 2345 6789', f.inputDigit('9'));
// +81 222 12 5678
f.clear();
assertEquals('+', f.inputDigit('+'));
assertEquals('+8', f.inputDigit('8'));
assertEquals('+81 ', f.inputDigit('1'));
assertEquals('+81 2', f.inputDigit('2'));
assertEquals('+81 22', f.inputDigit('2'));
assertEquals('+81 22 2', f.inputDigit('2'));
assertEquals('+81 22 21', f.inputDigit('1'));
assertEquals('+81 2221 2', f.inputDigit('2'));
assertEquals('+81 222 12 5', f.inputDigit('5'));
assertEquals('+81 222 12 56', f.inputDigit('6'));
assertEquals('+81 222 12 567', f.inputDigit('7'));
assertEquals('+81 222 12 5678', f.inputDigit('8'));
// +81 3332 2 5678
f.clear();
assertEquals('+', f.inputDigit('+'));
assertEquals('+8', f.inputDigit('8'));
assertEquals('+81 ', f.inputDigit('1'));
assertEquals('+81 3', f.inputDigit('3'));
assertEquals('+81 33', f.inputDigit('3'));
assertEquals('+81 33 3', f.inputDigit('3'));
assertEquals('+81 3332', f.inputDigit('2'));
assertEquals('+81 3332 2', f.inputDigit('2'));
assertEquals('+81 3332 2 5', f.inputDigit('5'));
assertEquals('+81 3332 2 56', f.inputDigit('6'));
assertEquals('+81 3332 2 567', f.inputDigit('7'));
assertEquals('+81 3332 2 5678', f.inputDigit('8'));
}

+ 26
- 2
javascript/i18n/phonenumbers/demo.html View File

@ -31,6 +31,7 @@ limitations under the License.
<script src="phonenumber.pb.js"></script>
<script src="metadata.js"></script>
<script src="phonenumberutil.js"></script>
<script src="asyoutypeformatter.js"></script>
</head>
<body>
@ -39,10 +40,11 @@ function phoneNumberParser() {
var $ = goog.dom.getElement;
var phoneNumber = $('phoneNumber').value;
var regionCode = $('defaultCountry').value;
var carrierCode = $('carrierCode').value;
var output = new goog.string.StringBuffer();
try {
var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
var number = phoneUtil.parse(phoneNumber, regionCode);
var number = phoneUtil.parseAndKeepRawInput(phoneNumber, regionCode);
output.append('****Parsing Result:****\n');
output.append(goog.json.serialize(new goog.proto2.ObjectSerializer(
goog.proto2.ObjectSerializer.KeyOption.NAME).serialize(number)));
@ -86,6 +88,8 @@ function phoneNumberParser() {
}
var PNF = i18n.phonenumbers.PhoneNumberFormat;
output.append('\n\n****Formatting Results:**** ');
output.append('\nOriginal format: ');
output.append(phoneUtil.formatInOriginalFormat(number, regionCode));
output.append('\nE164 format: ');
output.append(phoneUtil.format(number, PNF.E164));
output.append('\nInternational format: ');
@ -94,6 +98,21 @@ function phoneNumberParser() {
output.append(phoneUtil.format(number, PNF.NATIONAL));
output.append('\nOut-of-country format from US: ');
output.append(phoneUtil.formatOutOfCountryCallingNumber(number, 'US'));
if (carrierCode.length > 0) {
output.append('\nNational format with carrier code: ');
output.append(phoneUtil.formatNationalNumberWithCarrierCode(number,
carrierCode));
}
output.append('\n\n****AsYouTypeFormatter Results****');
var formatter = new i18n.phonenumbers.AsYouTypeFormatter(regionCode);
var phoneNumberLength = phoneNumber.length;
for (var i = 0; i < phoneNumberLength; ++i) {
var inputChar = phoneNumber.charAt(i);
output.append('\nChar entered: ');
output.append(inputChar);
output.append(' Output: ');
output.append(formatter.inputDigit(inputChar));
}
} catch (e) {
output.append('\n' + e);
}
@ -114,10 +133,15 @@ function phoneNumberParser() {
<input type="text" name="defaultCountry" id="defaultCountry" size="2" />
(ISO 3166-1 two-letter country code)
</p>
<p>
Specify a Carrier Code:
<input type="text" name="carrierCode" id="carrierCode" size="2" />
(optional, only valid for some countries)
</p>
<input type="submit" value="Submit" onclick="return phoneNumberParser();" />
<input type="reset" value="Reset" />
<p>
<textarea id="output" rows="15" cols="60"></textarea>
<textarea id="output" rows="30" cols="80"></textarea>
</p>
</form>


+ 1205
- 532
javascript/i18n/phonenumbers/metadata.js
File diff suppressed because it is too large
View File


+ 175
- 64
javascript/i18n/phonenumbers/metadatafortesting.js View File

@ -14,7 +14,7 @@
/**
* @fileoverview Generated metadata for file
* PhoneNumberMetaDataForTesting.xml
* java/resources/com/google/i18n/phonenumbers/test/PhoneNumberMetaDataForTesting.xml
* @author Nikolaos Trogkanis
*/
@ -38,7 +38,9 @@ i18n.phonenumbers.metadata.countryCodeToRegionCodeMap = {
61: ['AU'],
64: ['NZ'],
65: ['SG'],
81: ['JP'],
82: ['KR'],
244: ['AO'],
262: ['RE','YT'],
376: ['AD']
};
@ -57,6 +59,18 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,[,,"NA","NA"]
,[,,"NA","NA"]
,"AD",376,"00",,,,,,,1]
,
"AO": [,[,,"[29]\\d{8}","\\d{9}"]
,[,,"2\\d(?:[26-9]\\d|\\d[26-9])\\d{5}","\\d{9}",,,"222123456"]
,[,,"9[1-3]\\d{7}","\\d{9}",,,"923123456"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,"AO",244,"00",,,,,,,,[[,"(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",,"",""]
]
]
,
"AR": [,[,,"[1-3689]\\d{9,10}","\\d{6,11}"]
,[,,"[1-3]\\d{9}","\\d{6,10}"]
@ -66,16 +80,29 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,"AR",54,"00","0",,,"0(?:(11|343|3715)15)?","9$1",,,[[,"(\\d{2})(\\d{4})(\\d{4})","$1 $2-$3","11","0$1",""],
[,"(\\d{4})(\\d{2})(\\d{4})","$1 $2-$3","1[02-9]|[23]","0$1",""],
[,"9(11)(\\d{4})(\\d{4})","$1 15 $2-$3","911","0$1",""],
[,"9(\\d{4})(\\d{2})(\\d{4})","$1 $2-$3","9(?:1[02-9]|[23])","0$1","$1 $CC"],
[,"(\\d{3})(\\d{3})(\\d{4})","$1-$2-$3","[68]","0$1",""]]
,[[,"(\\d{2})(\\d{4})(\\d{4})","$1 $2-$3","11",,""],
[,"(\\d{4})(\\d{2})(\\d{4})","$1 $2-$3","1[02-9]|[23]",,""],
[,"(9)(11)(\\d{4})(\\d{4})","$1 $2 $3 $4","911",,""],
[,"(9)(\\d{4})(\\d{2})(\\d{4})","$1 $2 $3 $4","9(?:1[02-9]|[23])",,""],
[,"(\\d{3})(\\d{3})(\\d{4})","$1-$2-$3","[68]",,""]]]
,"AR",54,"00","0",,,"0(?:(11|343|3715)15)?","9$1",,,[[,"(\\d{2})(\\d{4})(\\d{4})","$1 $2-$3",["11"]
,"0$1",""]
,[,"(\\d{4})(\\d{2})(\\d{4})","$1 $2-$3",["1[02-9]|[23]"]
,"0$1",""]
,[,"9(11)(\\d{4})(\\d{4})","$1 15 $2-$3",["911"]
,"0$1",""]
,[,"9(\\d{4})(\\d{2})(\\d{4})","$1 $2-$3",["9(?:1[02-9]|[23])"]
,"0$1","$1 $CC"]
,[,"(\\d{3})(\\d{3})(\\d{4})","$1-$2-$3",["[68]"]
,"0$1",""]
]
,[[,"(\\d{2})(\\d{4})(\\d{4})","$1 $2-$3",["11"]
,,""]
,[,"(\\d{4})(\\d{2})(\\d{4})","$1 $2-$3",["1[02-9]|[23]"]
,,""]
,[,"(9)(11)(\\d{4})(\\d{4})","$1 $2 $3 $4",["911"]
,,""]
,[,"(9)(\\d{4})(\\d{2})(\\d{4})","$1 $2 $3 $4",["9(?:1[02-9]|[23])"]
,,""]
,[,"(\\d{3})(\\d{3})(\\d{4})","$1-$2-$3",["[68]"]
,,""]
]
]
,
"AU": [,[,,"[1-578]\\d{4,14}","\\d{5,15}"]
,[,,"[2378]\\d{8}","\\d{9}"]
@ -85,8 +112,12 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,"AU",61,"001[12]","0",,,"0",,"0011",,[[,"(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3","1","$1",""],
[,"(\\d{1})(\\d{4})(\\d{4})","$1 $2 $3","[2-478]","0$1",""]]]
,"AU",61,"001[12]","0",,,"0",,"0011",,[[,"(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3",["1"]
,"$1",""]
,[,"(\\d{1})(\\d{4})(\\d{4})","$1 $2 $3",["[2-478]"]
,"0$1",""]
]
]
,
"BS": [,[,,"(242|8(00|66|77|88)|900)\\d{7}","\\d{7,10}"]
,[,,"242(?:3(?:02|[236][1-9]|4[0-24-9]|5[0-68]|7[3-57]|9[2-5])|4(?:2[237]|51|64|77)|502|636|702)\\d{4}","\\d{7,10}"]
@ -96,7 +127,7 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,"BS",1,"011",,,,,,,,[[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",,"",""]]]
,"BS",1,"011"]
,
"DE": [,[,,"\\d{4,14}","\\d{2,14}"]
,[,,"(?:[24-6]\\d{2}|3[03-9]\\d|[789](?:[1-9]\\d|0[2-9]))\\d{3,8}","\\d{2,14}",,,"30123456"]
@ -106,12 +137,18 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,"DE",49,"00","0",,,"0",,,,[[,"(\\d{3})(\\d{3,8})","$1 $2","2|3[3-9]|906|[4-9][1-9]1","0$1",""],
[,"(\\d{2})(\\d{4,9})","$1 $2","[34]0|[68]9","0$1",""],
[,"([4-9]\\d{3})(\\d{2,7})","$1 $2","[4-9]","0$1",""],
[,"(\\d{3})(\\d{1})(\\d{6})","$1 $2 $3","800","0$1",""],
[,"(\\d{3})(\\d{3})(d{4})","$1 $2 $3","900[135]","0$1",""],
[,"(\\d{3})(\\d{4})(\\d{4})","$1 $2 $3","9009","0$1",""]]]
,"DE",49,"00","0",,,"0",,,,[[,"(\\d{3})(\\d{3,8})","$1 $2",["2|3[3-9]|906|[4-9][1-9]1"]
,"0$1",""]
,[,"(\\d{2})(\\d{4,9})","$1 $2",["[34]0|[68]9"]
,"0$1",""]
,[,"([4-9]\\d{3})(\\d{2,7})","$1 $2",["[4-9]","[4-6]|[7-9](?:\\d[1-9]|[1-9]\\d)"]
,"0$1",""]
,[,"(\\d{3})(\\d{1})(\\d{6})","$1 $2 $3",["800"]
,"0$1",""]
,[,"(\\d{3})(\\d{3,4})(\\d{4})","$1 $2 $3",["900"]
,"0$1",""]
]
]
,
"GB": [,[,,"\\d{10}","\\d{6,10}"]
,[,,"[1-6]\\d{9}","\\d{6,10}"]
@ -121,10 +158,16 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,[,,"8(?:4[3-5]|7[0-2])\\d{7}","\\d{10}"]
,[,,"70\\d{8}","\\d{10}"]
,[,,"56\\d{8}","\\d{10}"]
,"GB",44,"00","0",,,"0",,,,[[,"(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3","[1-59]|[78]0","(0$1)",""],
[,"(\\d)(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3 $4","6","(0$1)",""],
[,"(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3","7[1-57-9]","(0$1)",""],
[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","8[47]","(0$1)",""]]]
,"GB",44,"00","0",,,"0",,,,[[,"(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["[1-59]|[78]0"]
,"(0$1)",""]
,[,"(\\d)(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3 $4",["6"]
,"(0$1)",""]
,[,"(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3",["7[1-57-9]"]
,"(0$1)",""]
,[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["8[47]"]
,"(0$1)",""]
]
]
,
"IT": [,[,,"[0389]\\d{5,10}","\\d{6,11}"]
,[,,"0\\d{9,10}","\\d{10,11}"]
@ -134,31 +177,70 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,"IT",39,"00",,,,,,,,[[,"(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3","0[26]","",""],
[,"(\\d{3})(\\d{4})(\\d{3,4})","$1 $2 $3","0[13-57-9]","",""],
[,"(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3","3","",""],
[,"(\\d{3})(\\d{3,6})","$1 $2","8","",""]]]
,"IT",39,"00",,,,,,,,[[,"(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["0[26]"]
,"",""]
,[,"(\\d{3})(\\d{4})(\\d{3,4})","$1 $2 $3",["0[13-57-9]"]
,"",""]
,[,"(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3",["3"]
,"",""]
,[,"(\\d{3})(\\d{3,6})","$1 $2",["8"]
,"",""]
]
]
,
"KR": [,[,,"[1-79]\\d{3,9}|8\\d{8}","\\d{4,10}"]
,[,,"[1-79]\\d{3,9}|8\\d{8}","\\d{4,10}"]
,[,,"[1-79]\\d{3,9}|8\\d{8}","\\d{4,10}"]
"JP": [,[]
,[]
,[]
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,"KR",82,"00(?:[124-68]|[37]\\d{2})","0",,,"0(?:8[1-46-8]|85\\d{2})?",,,1,[[,"(\\d{2})(\\d{4})(\\d{4})","$1-$2-$3","1(?:0|1[19]|[69]9|5(?:44|59|8))|[57]0","0$1",""],
[,"(\\d{2})(\\d{3})(\\d{4})","$1-$2-$3","1(?:[169][2-8]|[78]|5(?:[1-3]|4[56]))|[68]0|[3-9][1-9][2-9]","0$1",""],
[,"(\\d{3})(\\d)(\\d{4})","$1-$2-$3","1312","0$1",""],
[,"(\\d{3})(\\d{2})(\\d{4})","$1-$2-$3","131[13-9]","0$1",""],
[,"(\\d{3})(\\d{3})(\\d{4})","$1-$2-$3","13[2-9]","0$1",""],
[,"(\\d{2})(\\d{2})(\\d{3})(\\d{4})","$1-$2-$3-$4","30","0$1",""],
[,"(\\d)(\\d{4})(\\d{4})","$1-$2-$3","2(?:[26]|3(?:01|1[45]|2[17-9]|39|4|6[67]|7[078]))","0$1",""],
[,"(\\d)(\\d{3})(\\d{4})","$1-$2-$3","2(?:3(?:0[02-9]|1[0-36-9]|2[02-6]|3[0-8]|6[0-589]|7[1-69]|[589])|[457-9])","0$1",""],
[,"(\\d)(\\d{3})","$1-$2","21(?:[0-247-9]|3[124]|6[1269])","0$1",""],
[,"(\\d)(\\d{4})","$1-$2","21(?:3[035-9]|6[03-578])","0$1",""],
[,"(\\d{2})(\\d{3})","$1-$2","[3-9][1-9]1(?:[0-247-9]|3[124]|6[1269])","0$1",""],
[,"(\\d{2})(\\d{4})","$1-$2","[3-9][1-9]1(?:3[035-9]|6[03-578])","0$1",""]]]
,"JP",81,"010","0",,,"0",,,1,[[,"(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["[57-9]0"]
,"0$1",""]
,[,"(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["222|333","(?:222|333)1","(?:222|333)11"]
,"0$1",""]
,[,"(\\d{4})(\\d)(\\d{4})","$1 $2 $3",["222|333","2221|3332","22212|3332","222120|3332"]
,"0$1",""]
,[,"(\\d{3})(\\d{2})(\\d{4})","$1 $2 $3",["[23]"]
,"0$1",""]
]
]
,
"KR": [,[,,"[1-79]\\d{3,9}|8\\d{8}","\\d{4,10}"]
,[,,"(?:2|[34][1-3]|5[1-5]|6[1-4])(?:1\\d{2,3}|[2-9]\\d{6,7})","\\d{4,10}",,,"22123456"]
,[,,"1[0-25-9]\\d{7,8}","\\d{9,10}",,,"1023456789"]
,[,,"80\\d{7}","\\d{9}",,,"801234567"]
,[,,"60[2-9]\\d{6}","\\d{9}",,,"602345678"]
,[,,"NA","NA"]
,[,,"50\\d{8}","\\d{10}",,,"5012345678"]
,[,,"70\\d{8}","\\d{10}",,,"7012345678"]
,"KR",82,"00(?:[124-68]|[37]\\d{2})","0",,,"0(?:8[1-46-8]|85\\d{2})?",,,,[[,"(\\d{2})(\\d{4})(\\d{4})","$1-$2-$3",["1(?:0|1[19]|[69]9|5[458])|[57]0","1(?:0|1[19]|[69]9|5(?:44|59|8))|[57]0"]
,"0$1",""]
,[,"(\\d{2})(\\d{3})(\\d{4})","$1-$2-$3",["1(?:[169][2-8]|[78]|5[1-4])|[68]0|[3-9][1-9][2-9]","1(?:[169][2-8]|[78]|5(?:[1-3]|4[56]))|[68]0|[3-9][1-9][2-9]"]
,"0$1",""]
,[,"(\\d{3})(\\d)(\\d{4})","$1-$2-$3",["131","1312"]
,"0$1",""]
,[,"(\\d{3})(\\d{2})(\\d{4})","$1-$2-$3",["131","131[13-9]"]
,"0$1",""]
,[,"(\\d{3})(\\d{3})(\\d{4})","$1-$2-$3",["13[2-9]"]
,"0$1",""]
,[,"(\\d{2})(\\d{2})(\\d{3})(\\d{4})","$1-$2-$3-$4",["30"]
,"0$1",""]
,[,"(\\d)(\\d{4})(\\d{4})","$1-$2-$3",["2(?:[26]|3[0-467])","2(?:[26]|3(?:01|1[45]|2[17-9]|39|4|6[67]|7[078]))"]
,"0$1",""]
,[,"(\\d)(\\d{3})(\\d{4})","$1-$2-$3",["2(?:3[0-35-9]|[457-9])","2(?:3(?:0[02-9]|1[0-36-9]|2[02-6]|3[0-8]|6[0-589]|7[1-69]|[589])|[457-9])"]
,"0$1",""]
,[,"(\\d)(\\d{3})","$1-$2",["21[0-46-9]","21(?:[0-247-9]|3[124]|6[1269])"]
,"0$1",""]
,[,"(\\d)(\\d{4})","$1-$2",["21[36]","21(?:3[035-9]|6[03-578])"]
,"0$1",""]
,[,"(\\d{2})(\\d{3})","$1-$2",["[3-9][1-9]1","[3-9][1-9]1(?:[0-46-9])","[3-9][1-9]1(?:[0-247-9]|3[124]|6[1269])"]
,"0$1",""]
,[,"(\\d{2})(\\d{4})","$1-$2",["[3-9][1-9]1","[3-9][1-9]1[36]","[3-9][1-9]1(?:3[035-9]|6[03-578])"]
,"0$1",""]
]
]
,
"MX": [,[,,"[1-9]\\d{9,10}","\\d{7,11}"]
,[,,"[2-9]\\d{9}","\\d{7,10}"]
@ -168,16 +250,29 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,"MX",52,"00","01",,,"01|04[45](\\d{10})","1$1",,,[[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","[89]00","",""],
[,"(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3","33|55|81","",""],
[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","[2467]|3[0-24-9]|5[0-46-9]|8[2-9]|9[1-9]","",""],
[,"1(\\d{2})(\\d{4})(\\d{4})","045 $1 $2 $3","1(?:33|55|81)","",""],
[,"1(\\d{3})(\\d{3})(\\d{4})","045 $1 $2 $3","1(?:[124579]|3[0-24-9]|5[0-46-9]|8[02-9])","",""]]
,[[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","[89]00",,""],
[,"(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3","33|55|81",,""],
[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","[2467]|3[0-24-9]|5[0-46-9]|8[2-9]|9[1-9]",,""],
[,"(1)(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3 $4","1(?:33|55|81)",,""],
[,"(1)(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3 $4","1(?:[124579]|3[0-24-9]|5[0-46-9]|8[02-9])",,""]]]
,"MX",52,"00","01",,,"01|04[45](\\d{10})","1$1",,,[[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["[89]00"]
,"",""]
,[,"(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["33|55|81"]
,"",""]
,[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["[2467]|3[0-24-9]|5[0-46-9]|8[2-9]|9[1-9]"]
,"",""]
,[,"1(\\d{2})(\\d{4})(\\d{4})","045 $1 $2 $3",["1(?:33|55|81)"]
,"",""]
,[,"1(\\d{3})(\\d{3})(\\d{4})","045 $1 $2 $3",["1(?:[124579]|3[0-24-9]|5[0-46-9]|8[02-9])"]
,"",""]
]
,[[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["[89]00"]
,,""]
,[,"(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["33|55|81"]
,,""]
,[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["[2467]|3[0-24-9]|5[0-46-9]|8[2-9]|9[1-9]"]
,,""]
,[,"(1)(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3 $4",["1(?:33|55|81)"]
,,""]
,[,"(1)(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3 $4",["1(?:[124579]|3[0-24-9]|5[0-46-9]|8[02-9])"]
,,""]
]
]
,
"NZ": [,[,,"[2-9]\\d{7,9}","\\d{7,10}"]
,[,,"24099\\d{3}|(?:3[2-79]|[479][2-689]|6[235-9])\\d{6}","\\d{7,8}"]
@ -187,9 +282,14 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,"NZ",64,"00","0",,,"0",,,,[[,"(\\d)(\\d{3})(\\d{4})","$1-$2 $3","24|[34679]","0$1",""],
[,"(\\d)(\\d{3})(\\d{3,5})","$1-$2 $3","2[179]","0$1",""],
[,"(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3","[89]","0$1",""]]]
,"NZ",64,"00","0",,,"0",,,,[[,"(\\d)(\\d{3})(\\d{4})","$1-$2 $3",["24|[34679]"]
,"0$1",""]
,[,"(\\d)(\\d{3})(\\d{3,5})","$1-$2 $3",["2[179]"]
,"0$1",""]
,[,"(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3",["[89]"]
,"0$1",""]
]
]
,
"PL": [,[,,"[1-9]\\d{8}","\\d{9}"]
,[,,"[1-9]\\d{8}","\\d{9}"]
@ -199,7 +299,9 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,"PL",48,"0~0","0",,,"0",,,,[[,"(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",,"0$1",""]]]
,"PL",48,"0~0","0",,,"0",,,,[[,"(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",,"0$1",""]
]
]
,
"RE": [,[,,"[268]\\d{8}","\\d{9}"]
,[,,"262\\d{6}","\\d{9}",,,"262161234"]
@ -209,7 +311,8 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,"RE",262,"00","0",,,"0",,,,[[,"([268]\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,"0$1",""]]
,"RE",262,"00","0",,,"0",,,,[[,"([268]\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,"0$1",""]
]
,,,,"262|6(?:9[23]|47)|8"]
,
"SG": [,[,,"[13689]\\d{7,10}","\\d{8,11}"]
@ -220,9 +323,14 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,"SG",65,"0[0-3][0-9]",,,,,,,,[[,"(\\d{4})(\\d{4})","$1 $2","[369]|8[1-9]","",""],
[,"(\\d{4})(\\d{3})(\\d{4})","$1 $2 $3","1[89]","",""],
[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","800","",""]]]
,"SG",65,"0[0-3][0-9]",,,,,,,,[[,"(\\d{4})(\\d{4})","$1 $2",["[369]|8[1-9]"]
,"",""]
,[,"(\\d{4})(\\d{3})(\\d{4})","$1 $2 $3",["1[89]"]
,"",""]
,[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["800"]
,"",""]
]
]
,
"US": [,[,,"[13-9]\\d{9}|2[0-35-9]\\d{8}","\\d{7,10}",,,"1234567890"]
,[,,"[13-9]\\d{9}|2[0-35-9]\\d{8}","\\d{7,10}",,,"1234567890"]
@ -232,9 +340,12 @@ i18n.phonenumbers.metadata.countryToMetadata = {
,[,,"NA","NA"]
,[,,"NA","NA"]
,[,,"NA","NA"]
,"US",1,"011",," extn. ",,,,,1,[[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",,"",""],
[,"(\\d{3})(\\d{4})","$1 $2",,"",""]]
,,,1]
,"US",1,"011","1"," extn. ",,"1",,,1,[[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",,"",""]
,[,"(\\d{3})(\\d{4})","$1 $2",,"",""]
]
,[[,"(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",,,""]
]
,,1]
,
"YT": [,[,,"[268]\\d{8}","\\d{9}"]
,[,,"2696[0-4]\\d{4}","\\d{9}",,,"269601234"]


+ 3615
- 0
javascript/i18n/phonenumbers/metadatalite.js
File diff suppressed because it is too large
View File


+ 29
- 17
javascript/i18n/phonenumbers/phonemetadata.pb.js View File

@ -142,54 +142,65 @@ i18n.phonenumbers.NumberFormat.prototype.clearFormat = function() {
/**
* Gets the value of the leading_digits field.
* Gets the value of the leading_digits_pattern field at the index given.
* @param {number} index The index to lookup.
* @return {?string} The value.
*/
i18n.phonenumbers.NumberFormat.prototype.getLeadingDigits = function() {
return /** @type {?string} */ (this.get$Value(3));
i18n.phonenumbers.NumberFormat.prototype.getLeadingDigitsPattern = function(index) {
return /** @type {?string} */ (this.get$Value(3, index));
};
/**
* Gets the value of the leading_digits field or the default value if not set.
* Gets the value of the leading_digits_pattern field at the index given or the default value if not set.
* @param {number} index The index to lookup.
* @return {string} The value.
*/
i18n.phonenumbers.NumberFormat.prototype.getLeadingDigitsOrDefault = function() {
return /** @type {string} */ (this.get$ValueOrDefault(3));
i18n.phonenumbers.NumberFormat.prototype.getLeadingDigitsPatternOrDefault = function(index) {
return /** @type {string} */ (this.get$ValueOrDefault(3, index));
};
/**
* Sets the value of the leading_digits field.
* @param {string} value The value.
* Adds a value to the leading_digits_pattern field.
* @param {string} value The value to add.
*/
i18n.phonenumbers.NumberFormat.prototype.setLeadingDigits = function(value) {
this.set$Value(3, /** @type {Object} */ (value));
i18n.phonenumbers.NumberFormat.prototype.addLeadingDigitsPattern = function(value) {
this.add$Value(3, /** @type {Object} */ (value));
};
/**
* Returns whether the leading_digits field has a value.
* Returns the array of values in the leading_digits_pattern field.
* @return {Array.<string>} The values in the field.
*/
i18n.phonenumbers.NumberFormat.prototype.leadingDigitsPatternArray = function() {
return /** @type {Array.<string>} */ (this.array$Values(3));
};
/**
* Returns whether the leading_digits_pattern field has a value.
* @return {boolean} true if the field has a value.
*/
i18n.phonenumbers.NumberFormat.prototype.hasLeadingDigits = function() {
i18n.phonenumbers.NumberFormat.prototype.hasLeadingDigitsPattern = function() {
return this.has$Value(3);
};
/**
* Gets the number of values in the leading_digits field.
* Gets the number of values in the leading_digits_pattern field.
* @return {number}
*/
i18n.phonenumbers.NumberFormat.prototype.leadingDigitsCount = function() {
i18n.phonenumbers.NumberFormat.prototype.leadingDigitsPatternCount = function() {
return this.count$Values(3);
};
/**
* Clears the values in the leading_digits field.
* Clears the values in the leading_digits_pattern field.
*/
i18n.phonenumbers.NumberFormat.prototype.clearLeadingDigits = function() {
i18n.phonenumbers.NumberFormat.prototype.clearLeadingDigitsPattern = function() {
this.clear$Field(3);
};
@ -1714,7 +1725,8 @@ goog.proto2.Message.set$Metadata(i18n.phonenumbers.NumberFormat, {
type: String
},
'3' : {
name: 'leading_digits',
name: 'leading_digits_pattern',
repeated: true,
fieldType: goog.proto2.Message.FieldType.STRING,
type: String
},


+ 262
- 159
javascript/i18n/phonenumbers/phonenumberutil.js View File

@ -436,7 +436,7 @@ i18n.phonenumbers.PhoneNumberUtil.KNOWN_EXTN_PATTERNS_ =
'[ \u00A0\\t,]*' + '(?:ext(?:ensio)?n?|\uFF45\uFF58\uFF54\uFF4E?|' +
'[,x\uFF58#\uFF03~\uFF5E]|int|anexo|\uFF49\uFF4E\uFF54)' +
'[:\\.\uFF0E]?[ \u00A0\\t,-]*([' +
i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{1,7})|[- ]+([' +
i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{1,7})#?|[- ]+([' +
i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{1,5})#';
/**
@ -494,12 +494,6 @@ i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_ = /\$FG/;
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.CC_PATTERN_ = /\$CC/;
/**
* @const
* @type {RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.NON_DIGIT_PATTERN_ = /\D/;
/**
* INTERNATIONAL and NATIONAL formats are consistent with the definition in
@ -765,8 +759,9 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfGeographicalAreaCode =
}
/** @type {i18n.phonenumbers.PhoneNumberType} */
var type = this.getNumberTypeHelper_('' + number.getNationalNumber(),
metadata);
var type = this.getNumberTypeHelper_(
i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number),
metadata);
// Most numbers other than the two types below have to be dialled in full.
if (type != i18n.phonenumbers.PhoneNumberType.FIXED_LINE &&
type != i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE) {
@ -780,7 +775,7 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfGeographicalAreaCode =
// include the extension when we format it, so we copy it and clear the
// extension here.
copiedProto = new i18n.phonenumbers.PhoneNumber();
copiedProto.values_ = goog.cloneObject(number.values_);
copiedProto.mergeFrom(number);
copiedProto.clearExtension();
} else {
copiedProto = number;
@ -791,7 +786,7 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfGeographicalAreaCode =
i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
/** @type {!Array.<string>} */
var numberGroups = nationalSignificantNumber.split(
i18n.phonenumbers.PhoneNumberUtil.NON_DIGIT_PATTERN_);
i18n.phonenumbers.PhoneNumberUtil.NON_DIGITS_PATTERN_);
// The pattern will start with '+COUNTRY_CODE ' so the first group will always
// be the empty string (before the + symbol) and the second group will be the
// country code. The third group will be area code if it's not the last group.
@ -804,10 +799,6 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfGeographicalAreaCode =
if (numberGroups.length <= 2) {
return 0;
}
// Note all countries that use leading zero in national number currently don't
// use national prefix, so they won't have an area code, which means clients
// don't need to worry about appending the leading zero to the geographical
// area code they derive from the length we return here.
return numberGroups[1].length;
};
@ -884,8 +875,6 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.isValidRegionCode_ =
i18n.phonenumbers.PhoneNumberUtil.prototype.format =
function(number, numberFormat) {
/** @type {!goog.string.StringBuffer} */
var formattedNumber = new goog.string.StringBuffer();
/** @type {number} */
var countryCode = number.getCountryCodeOrDefault();
/** @type {string} */
@ -894,11 +883,9 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.format =
if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.E164) {
// Early exit for E164 case since no formatting of the national number needs
// to be applied. Extensions are not formatted.
formattedNumber.append(nationalSignificantNumber);
this.formatNumberByFormat_(countryCode,
i18n.phonenumbers.PhoneNumberFormat.E164,
formattedNumber);
return formattedNumber.toString();
return this.formatNumberByFormat_(countryCode,
i18n.phonenumbers.PhoneNumberFormat.E164,
nationalSignificantNumber, '');
}
// Note getRegionCodeForCountryCode() is used because formatting information
// for countries which share a country code is contained by only one country
@ -907,15 +894,20 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.format =
/** @type {string} */
var regionCode = this.getRegionCodeForCountryCode(countryCode);
if (!this.isValidRegionCode_(regionCode)) {
formattedNumber.append(nationalSignificantNumber);
return formattedNumber.toString();
return nationalSignificantNumber;
}
formattedNumber.append(this.formatNationalNumber_(nationalSignificantNumber,
regionCode, numberFormat));
this.maybeGetFormattedExtension_(number, regionCode, formattedNumber);
this.formatNumberByFormat_(countryCode, numberFormat, formattedNumber);
return formattedNumber.toString();
/** @type {string} */
var formattedExtension = this.maybeGetFormattedExtension_(number, regionCode);
/** @type {string} */
var formattedNationalNumber =
this.formatNationalNumber_(nationalSignificantNumber,
regionCode,
numberFormat);
return this.formatNumberByFormat_(countryCode,
numberFormat,
formattedNationalNumber,
formattedExtension);
};
/**
@ -950,6 +942,8 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.formatByPattern =
if (!this.isValidRegionCode_(regionCode)) {
return nationalSignificantNumber;
}
/** @type {Array.<i18n.phonenumbers.NumberFormat>} */
var userDefinedFormatsCopy = [];
/** @type {number} */
var size = userDefinedFormats.length;
for (var i = 0; i < size; ++i) {
@ -959,25 +953,48 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.formatByPattern =
var nationalPrefixFormattingRule =
numFormat.getNationalPrefixFormattingRuleOrDefault();
if (nationalPrefixFormattingRule.length > 0) {
// Before we do a replacement of the national prefix pattern $NP with the
// national prefix, we need to copy the rule so that subsequent
// replacements for different numbers have the appropriate national
// prefix.
/** type {i18n.phonenumbers.NumberFormat} */
var numFormatCopy = new i18n.phonenumbers.NumberFormat();
numFormatCopy.mergeFrom(numFormat);
/** @type {string} */
var nationalPrefix =
this.getMetadataForRegion(regionCode).getNationalPrefixOrDefault();
// Replace $NP with national prefix and $FG with the first group ($1).
nationalPrefixFormattingRule = nationalPrefixFormattingRule
.replace(i18n.phonenumbers.PhoneNumberUtil.NP_PATTERN_,
nationalPrefix)
.replace(i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_, '$1');
numFormat.setNationalPrefixFormattingRule(nationalPrefixFormattingRule);
if (nationalPrefix.length > 0) {
// Replace $NP with national prefix and $FG with the first group ($1).
nationalPrefixFormattingRule = nationalPrefixFormattingRule
.replace(i18n.phonenumbers.PhoneNumberUtil.NP_PATTERN_,
nationalPrefix)
.replace(i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_, '$1');
numFormatCopy.setNationalPrefixFormattingRule(
nationalPrefixFormattingRule);
} else {
// We don't want to have a rule for how to format the national prefix if
// there isn't one.
numFormatCopy.clearNationalPrefixFormattingRule();
}
userDefinedFormatsCopy.push(numFormatCopy);
} else {
// Otherwise, we just add the original rule to the modified list of
// formats.
userDefinedFormatsCopy.push(numFormat);
}
}
/** @type {!goog.string.StringBuffer} */
var formattedNumber = new goog.string.StringBuffer(
/** @type {string} */
var formattedExtension = this.maybeGetFormattedExtension_(number, regionCode);
/** @type {string} */
var formattedNationalNumber =
this.formatAccordingToFormats_(nationalSignificantNumber,
userDefinedFormats, numberFormat));
this.maybeGetFormattedExtension_(number, regionCode, formattedNumber);
this.formatNumberByFormat_(countryCode, numberFormat, formattedNumber);
return formattedNumber.toString();
userDefinedFormatsCopy,
numberFormat);
return this.formatNumberByFormat_(countryCode,
numberFormat,
formattedNationalNumber,
formattedExtension);
};
/**
@ -1003,18 +1020,18 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.
return nationalSignificantNumber;
}
/** @type {!goog.string.StringBuffer} */
var formattedNumber = new goog.string.StringBuffer(
/** @type {string} */
var formattedExtension = this.maybeGetFormattedExtension_(number, regionCode);
/** @type {string} */
var formattedNationalNumber =
this.formatNationalNumber_(nationalSignificantNumber,
regionCode,
i18n.phonenumbers.PhoneNumberFormat.NATIONAL,
carrierCode));
this.maybeGetFormattedExtension_(number, regionCode, formattedNumber);
this.formatNumberByFormat_(countryCode,
i18n.phonenumbers.PhoneNumberFormat.NATIONAL,
formattedNumber);
return formattedNumber.toString();
}
carrierCode);
return this.formatNumberByFormat_(
countryCode, i18n.phonenumbers.PhoneNumberFormat.NATIONAL,
formattedNationalNumber, formattedExtension);
};
/**
* Formats a phone number for out-of-country dialing purpose. If no
@ -1080,6 +1097,8 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.formatOutOfCountryCallingNumber =
var metadata = this.getMetadataForRegion(countryCallingFrom);
/** @type {string} */
var internationalPrefix = metadata.getInternationalPrefixOrDefault();
/** @type {string} */
var formattedExtension = this.maybeGetFormattedExtension_(number, regionCode);
// For countries that have multiple international prefixes, the international
// format of the number is returned, unless there is a preferred international
@ -1095,17 +1114,12 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.formatOutOfCountryCallingNumber =
metadata.getPreferredInternationalPrefixOrDefault();
}
/** @type {!goog.string.StringBuffer} */
var formattedNumber = new goog.string.StringBuffer(formattedNationalNumber);
this.maybeGetFormattedExtension_(number, regionCode, formattedNumber);
if (internationalPrefixForFormatting.length > 0) {
return internationalPrefixForFormatting + ' ' + countryCode + ' ' +
formattedNumber.toString();
} else {
this.formatNumberByFormat_(countryCode,
i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL, formattedNumber);
}
return formattedNumber.toString();
return internationalPrefixForFormatting != '' ?
internationalPrefixForFormatting + ' ' + countryCode + ' ' +
formattedNationalNumber + formattedExtension :
this.formatNumberByFormat_(
countryCode, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL,
formattedNationalNumber, formattedExtension);
};
/**
@ -1178,30 +1192,25 @@ i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber =
* @param {number} countryCode the country calling code.
* @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
* phone number should be formatted into.
* @param {!goog.string.StringBuffer} formattedNumber the formatted phone
* number.
* @param {string} formattedNationalNumber
* @param {string} formattedExtension
* @return {string} the formatted phone number.
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.formatNumberByFormat_ =
function(countryCode, numberFormat, formattedNumber) {
function(countryCode, numberFormat,
formattedNationalNumber, formattedExtension) {
switch (numberFormat) {
case i18n.phonenumbers.PhoneNumberFormat.E164:
/** @type {string} */
var a = formattedNumber.toString();
formattedNumber.clear();
formattedNumber.append(i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN +
countryCode + a);
return;
return i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCode +
formattedNationalNumber + formattedExtension;
case i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL:
a = formattedNumber.toString();
formattedNumber.clear();
formattedNumber.append(i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN +
countryCode + ' ' + a);
return;
return i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCode + ' ' +
formattedNationalNumber + formattedExtension;
case i18n.phonenumbers.PhoneNumberFormat.NATIONAL:
default:
return;
return formattedNationalNumber + formattedExtension;
}
};
@ -1262,8 +1271,13 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.formatAccordingToFormats_ =
var l = availableFormats.length;
for (var i = 0; i < l; ++i) {
numFormat = availableFormats[i];
if (!numFormat.hasLeadingDigits() ||
nationalNumber.search(numFormat.getLeadingDigits()) == 0) {
/** @type {number} */
var size = numFormat.leadingDigitsPatternCount();
if (size == 0 ||
// We always use the last leading_digits_pattern, as it is the most
// detailed.
nationalNumber
.search(numFormat.getLeadingDigitsPattern(size - 1)) == 0) {
/** @type {RegExp} */
var patternToMatch = new RegExp(numFormat.getPattern());
/** @type {string} */
@ -1351,32 +1365,45 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumberForType =
};
/**
* Appends the formatted extension of a phone number to formattedNumber, if the
* phone number had an extension specified.
* Gets the formatted extension of a phone number, if the phone number had an
* extension specified. If not, it returns an empty string.
*
* @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber that might have
* an extension.
* @param {string} regionCode the ISO 3166-1 two-letter country code.
* @param {!goog.string.StringBuffer} formattedNumber the formatted phone
* number.
* @return {string} the formatted extension if any.
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.maybeGetFormattedExtension_ =
function(number, regionCode, formattedNumber) {
function(number, regionCode) {
if (number.hasExtension()) {
// Formats the extension part of the phone number by prefixing it with the
// appropriate extension prefix. This will be the default extension prefix,
// unless overridden by a preferred extension prefix for this country.
/** @type {i18n.phonenumbers.PhoneMetadata} */
var metadata = this.getMetadataForRegion(regionCode);
if (metadata.hasPreferredExtnPrefix()) {
formattedNumber.append(metadata.getPreferredExtnPrefix());
} else {
formattedNumber.append(
i18n.phonenumbers.PhoneNumberUtil.DEFAULT_EXTN_PREFIX_);
}
formattedNumber.append(number.getExtension());
if (!number.hasExtension()) {
return '';
} else {
return this.formatExtension_(number.getExtensionOrDefault(), regionCode);
}
};
/**
* Formats the extension part of the phone number by prefixing it with the
* appropriate extension prefix. This will be the default extension prefix,
* unless overridden by a preferred extension prefix for this country.
*
* @param {string} extensionDigits the extension digits.
* @param {string} regionCode the ISO 3166-1 two-letter country code.
* @return {string} the formatted extension.
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.formatExtension_ =
function(extensionDigits, regionCode) {
/** @type {i18n.phonenumbers.PhoneMetadata} */
var metadata = this.getMetadataForRegion(regionCode);
if (metadata.hasPreferredExtnPrefix()) {
return metadata.getPreferredExtnPrefix() + extensionDigits;
} else {
return i18n.phonenumbers.PhoneNumberUtil.DEFAULT_EXTN_PREFIX_ +
extensionDigits;
}
};
@ -1506,7 +1533,7 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.getMetadataForRegion =
var metadataSerialized =
i18n.phonenumbers.metadata.countryToMetadata[regionCode];
if (metadataSerialized == null) {
return null;
return null;
}
metadata = /** @type {i18n.phonenumbers.PhoneMetadata} */ (
serializer.deserialize(i18n.phonenumbers.PhoneMetadata.getDescriptor(),
@ -1713,6 +1740,19 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.isNANPACountry =
regionCode.toUpperCase());
};
/**
* Check whether countryCode represents the country calling code from a country
* whose national significant number could contain a leading zero. An example of
* such a country is Italy.
*
* @param {number} countryCode the country calling code.
* @return {boolean}
*/
i18n.phonenumbers.PhoneNumberUtil.isLeadingZeroCountry = function(countryCode) {
return countryCode in
i18n.phonenumbers.PhoneNumberUtil.LEADING_ZERO_COUNTRIES_;
};
/**
* Convenience wrapper around isPossibleNumberWithReason. Instead of returning
* the reason for failure, this method returns a boolean value.
@ -1728,19 +1768,6 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumber =
i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE;
};
/**
* Check whether countryCode represents the country calling code from a country
* whose national significant number could contain a leading zero. An example of
* such a country is Italy.
*
* @param {number} countryCode the country calling code.
* @return {boolean}
*/
i18n.phonenumbers.PhoneNumberUtil.isLeadingZeroCountry = function(countryCode) {
return countryCode in
i18n.phonenumbers.PhoneNumberUtil.LEADING_ZERO_COUNTRIES_;
};
/**
* Check whether a phone number is a possible number. It provides a more lenient
* check than isValidNumber in the following sense:
@ -1794,7 +1821,8 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberWithReason =
var numberLength = nationalNumber.length;
if (numberLength < i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT;
} else if (numberLength > i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_) {
} else if (numberLength >
i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_) {
return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_LONG;
} else {
return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE;
@ -1804,11 +1832,11 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberWithReason =
var possibleNumberPattern =
generalNumDesc.getPossibleNumberPatternOrDefault();
/** @type {Array.<string> } */
var a = nationalNumber.match('^' + possibleNumberPattern);
var matchedGroups = nationalNumber.match('^' + possibleNumberPattern);
/** @type {string} */
var m = a ? a[0] : '';
if (m.length > 0) {
return (m.length == nationalNumber.length) ?
var firstGroup = matchedGroups ? matchedGroups[0] : '';
if (firstGroup.length > 0) {
return (firstGroup.length == nationalNumber.length) ?
i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE :
i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_LONG;
} else {
@ -1849,6 +1877,39 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberString =
}
};
/**
* Attempts to extract a valid number from a phone number that is too long to be
* valid, and resets the PhoneNumber object passed in to that valid version. If
* no valid number could be extracted, the PhoneNumber object passed in will not
* be modified.
* @param {i18n.phonenumbers.PhoneNumber} number a PhoneNumber object which
* contains a number that is too long to be valid.
* @return {boolean} true if a valid phone number can be successfully extracted.
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.truncateTooLongNumber =
function(number) {
if (this.isValidNumber(number)) {
return true;
}
/** @type {i18n.phonenumbers.PhoneNumber} */
var numberCopy = new i18n.phonenumbers.PhoneNumber();
numberCopy.mergeFrom(number);
/** @type {number} */
var nationalNumber = number.getNationalNumberOrDefault();
do {
nationalNumber = Math.floor(nationalNumber / 10);
numberCopy.setNationalNumber(nationalNumber);
if (nationalNumber == 0 ||
this.isPossibleNumberWithReason(numberCopy) ==
i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT) {
return false;
}
} while (!this.isValidNumber(numberCopy));
number.setNationalNumber(nationalNumber);
return true;
};
/**
* Extracts country code from fullNumber, returns it and places the remaining
* number in nationalNumber. It assumes that the leading plus sign or IDD has
@ -1866,7 +1927,9 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.extractCountryCode =
var fullNumberStr = fullNumber.toString();
/** @type {number} */
var potentialCountryCode;
for (var i = 1; i <= 3; ++i) {
/** @type {number} */
var numberLength = fullNumberStr.length;
for (var i = 1; i <= 3 && i <= numberLength; ++i) {
potentialCountryCode = parseInt(fullNumberStr.substring(0, i), 10);
if (potentialCountryCode in
i18n.phonenumbers.metadata.countryCodeToRegionCodeMap) {
@ -1959,9 +2022,10 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.maybeExtractCountryCode =
// Check to see if the number is valid for the default region already. If
// not, we check to see if the country code for the default region is
// present at the start of the number.
/** @type {i18n.phonenumbers.PhoneNumberDesc} */
var generalDesc = defaultRegionMetadata.getGeneralDesc();
/** @type {RegExp} */
var validNumberPattern = new RegExp(defaultRegionMetadata.getGeneralDesc()
.getNationalNumberPattern());
var validNumberPattern = new RegExp(generalDesc.getNationalNumberPattern());
if (!i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
validNumberPattern, fullNumber.toString())) {
/** @type {number} */
@ -1981,8 +2045,19 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.maybeExtractCountryCode =
validNumberPattern);
/** @type {string} */
var potentialNationalNumberStr = potentialNationalNumber.toString();
/** @type {Array.<string> } */
var matchedGroups = potentialNationalNumberStr.match(
'^' + generalDesc.getPossibleNumberPattern());
/** @type {number} */
var possibleNumberMatchedLength = matchedGroups &&
matchedGroups[0] != null && matchedGroups[0].length || 0;
// If the resultant number is either valid, or still too long even with
// the country code stripped, we consider this a better result and keep
// the potential national number.
if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
validNumberPattern, potentialNationalNumberStr)) {
validNumberPattern, potentialNationalNumberStr) ||
possibleNumberMatchedLength > 0 &&
possibleNumberMatchedLength != potentialNationalNumberStr.length) {
nationalNumber.append(potentialNationalNumberStr);
if (storeCountryCodeSource) {
phoneNumber.setCountryCodeSource(
@ -2020,12 +2095,14 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.parsePrefixAsIdd_ =
/** @type {number} */
var matchEnd = numberStr.match(iddPattern)[0].length;
/** @type {Array.<string> } */
var a = numberStr.substring(matchEnd).match(
var matchedGroups = numberStr.substring(matchEnd).match(
i18n.phonenumbers.PhoneNumberUtil.CAPTURING_DIGIT_PATTERN_);
if (a && a[1] != null && a[1].length > 0) {
if (matchedGroups && matchedGroups[1] != null &&
matchedGroups[1].length > 0) {
/** @type {string} */
var normalizedGroup = i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(
a[1], i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS, true);
matchedGroups[1], i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS,
true);
if (normalizedGroup == '0') {
return false;
}
@ -2160,14 +2237,15 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.maybeStripExtension =
numberStr.substring(0, mStart))) {
// The numbers are captured into groups in the regular expression.
/** @type {Array.<string>} */
var a = numberStr.match(i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_);
var matchedGroups =
numberStr.match(i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_);
/** @type {number} */
var aLength = a.length;
for (var i = 1; i < aLength; ++i) {
if (a[i] != null && a[i].length > 0) {
var matchedGroupsLength = matchedGroups.length;
for (var i = 1; i < matchedGroupsLength; ++i) {
if (matchedGroups[i] != null && matchedGroups[i].length > 0) {
number.clear();
number.append(numberStr.substring(0, mStart));
return a[i];
return matchedGroups[i];
}
}
}
@ -2188,23 +2266,24 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.maybeStripExtension =
* denotes the country that we are expecting the number to be from. This is
* only used if the number being parsed is not written in international
* format. The country code for the number in this case would be stored as
* that of the default country supplied.
* that of the default country supplied. If the number is guaranteed to
* start with a '+' followed by the country code, then 'ZZ' or null can be
* supplied.
* @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
* with the parsed number.
* @throws {i18n.phonenumbers.Error}
* @throws {i18n.phonenumbers.Error} if the string is not considered to be a
* viable phone number or if no default country was supplied and the number
* is not in international format (does not start with +).
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.parse = function(numberToParse,
defaultCountry) {
/** @type {i18n.phonenumbers.PhoneNumber} */
var phoneNumber = new i18n.phonenumbers.PhoneNumber();
if (!this.isValidRegionCode_(defaultCountry)) {
if (numberToParse.charAt(0) !=
i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
}
}
this.parseHelper_(numberToParse, defaultCountry, false, phoneNumber);
return phoneNumber;
return this.parseHelper_(numberToParse, defaultCountry, false);
};
/**
@ -2220,32 +2299,28 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.parse = function(numberToParse,
* only used if the number being parsed is not written in international
* format. The country code for the number in this case would be stored as
* that of the default country supplied.
* @param {i18n.phonenumbers.PhoneNumber=} opt_phoneNumber mutable PhoneNumber
* to decrease object creation when invoked many times.
* @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
* with the parsed number.
* @throws {i18n.phonenumbers.Error}
* @throws {i18n.phonenumbers.Error} if the string is not considered to be a
* viable phone number or if no default country was supplied and the number
* is not in international format (does not start with +).
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.parseAndKeepRawInput =
function(numberToParse, defaultCountry, opt_phoneNumber) {
function(numberToParse, defaultCountry) {
/** @type {i18n.phonenumbers.PhoneNumber} */
var phoneNumber = opt_phoneNumber != null ?
opt_phoneNumber : new i18n.phonenumbers.PhoneNumber();
if (!this.isValidRegionCode_(defaultCountry)) {
if (numberToParse.charAt(0) !=
i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
}
}
this.parseHelper_(numberToParse, defaultCountry, true, phoneNumber);
return phoneNumber;
return this.parseHelper_(numberToParse, defaultCountry, true);
};
/**
* Parses a string and fills up the phoneNumber. This method is the same as the
* public parse() method, with the exception that it allows the default country
* to be null, for use by isNumberMatch().
* Parses a string and returns it in proto buffer format. This method is the
* same as the public parse() method, with the exception that it allows the
* default country to be null, for use by isNumberMatch().
*
* @param {string} numberToParse number that we are attempting to parse. This
* can contain formatting such as +, ( and -, as well as a phone number
@ -2257,13 +2332,13 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.parseAndKeepRawInput =
* that of the default country supplied.
* @param {boolean} keepRawInput whether to populate the raw_input field of the
* phoneNumber with numberToParse.
* @param {i18n.phonenumbers.PhoneNumber} phoneNumber the PhoneNumber object to
* populate.
* @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
* with the parsed number.
* @throws {i18n.phonenumbers.Error}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.parseHelper_ =
function(numberToParse, defaultCountry, keepRawInput, phoneNumber) {
function(numberToParse, defaultCountry, keepRawInput) {
// Extract a possible number from the string passed in (this strips leading
// characters that could not be the start of a phone number.)
@ -2274,6 +2349,8 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.parseHelper_ =
throw i18n.phonenumbers.Error.NOT_A_NUMBER;
}
/** @type {i18n.phonenumbers.PhoneNumber} */
var phoneNumber = new i18n.phonenumbers.PhoneNumber();
if (keepRawInput) {
phoneNumber.setRawInput(numberToParse);
}
@ -2345,6 +2422,7 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.parseHelper_ =
phoneNumber.setItalianLeadingZero(true);
}
phoneNumber.setNationalNumber(parseInt(normalizedNationalNumberStr, 10));
return phoneNumber;
};
/**
@ -2369,27 +2447,30 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.parseHelper_ =
* @return {i18n.phonenumbers.PhoneNumberUtil.MatchType} NO_MATCH,
* SHORT_NSN_MATCH, NSN_MATCH or EXACT_MATCH depending on the level of
* equality of the two numbers, described in the method definition.
* @throws {i18n.phonenumbers.Error}
* @throws {i18n.phonenumbers.Error} if either number is not considered to be
* a viable phone number.
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberMatch =
function(firstNumberIn, secondNumberIn) {
/** @type {i18n.phonenumbers.PhoneNumber} */
var firstNumber = new i18n.phonenumbers.PhoneNumber();
var firstNumber;
/** @type {i18n.phonenumbers.PhoneNumber} */
var secondNumber = new i18n.phonenumbers.PhoneNumber();
var secondNumber;
// If the input arguements are strings parse them to a proto buffer format.
// Else make copies of the phone numbers so that the numbers passed in are not
// edited.
if (typeof firstNumberIn == 'string') {
this.parseHelper_(firstNumberIn, null, false, firstNumber);
firstNumber = this.parseHelper_(firstNumberIn, null, false);
} else {
firstNumber.values_ = goog.cloneObject(firstNumberIn.values_);
firstNumber = new i18n.phonenumbers.PhoneNumber();
firstNumber.mergeFrom(firstNumberIn);
}
if (typeof secondNumberIn == 'string') {
this.parseHelper_(secondNumberIn, null, false, secondNumber);
secondNumber = this.parseHelper_(secondNumberIn, null, false);
} else {
secondNumber.values_ = goog.cloneObject(secondNumberIn.values_);
secondNumber = new i18n.phonenumbers.PhoneNumber();
secondNumber.mergeFrom(secondNumberIn);
}
// First clear raw_input and country_code_source field and any empty-string
// extensions so that
@ -2479,8 +2560,8 @@ i18n.phonenumbers.PhoneNumberUtil.prototype.isNationalNumberSuffixOfTheOther_ =
*/
i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_ = function(regex, str) {
/** @type {Array.<string>} */
var a = str.match(regex);
if (a && a[0].length == str.length) {
var matchedGroups = str.match(regex);
if (matchedGroups && matchedGroups[0].length == str.length) {
return true;
}
return false;
@ -2510,3 +2591,25 @@ i18n.phonenumbers.PhoneNumberDesc.prototype.exactlySameAs = function(other) {
this.getPossibleNumberPattern() == other.getPossibleNumberPattern() &&
this.getExampleNumber() == other.getExampleNumber();
};
/**
* @param {i18n.phonenumbers.PhoneNumber} other
* @return {i18n.phonenumbers.PhoneNumber}
*/
i18n.phonenumbers.PhoneNumber.prototype.mergeFrom = function(other) {
if (other) {
this.values_ = goog.cloneObject(other.values_);
}
return this;
};
/**
* @param {i18n.phonenumbers.NumberFormat} other
* @return {i18n.phonenumbers.NumberFormat}
*/
i18n.phonenumbers.NumberFormat.prototype.mergeFrom = function(other) {
if (other) {
this.values_ = goog.cloneObject(other.values_);
}
return this;
};

+ 118
- 20
javascript/i18n/phonenumbers/phonenumberutil_test.js View File

@ -30,7 +30,7 @@ function testGetInstanceLoadUSMetadata() {
assertEquals('US', metadata.getId());
assertEquals(1, metadata.getCountryCode());
assertEquals('011', metadata.getInternationalPrefix());
assertFalse(metadata.hasNationalPrefix());
assertTrue(metadata.hasNationalPrefix());
assertEquals(2, metadata.numberFormatCount());
assertEquals('(\\d{3})(\\d{3})(\\d{4})',
metadata.getNumberFormat(0).getPattern());
@ -56,11 +56,12 @@ function testGetInstanceLoadDEMetadata() {
assertEquals(49, metadata.getCountryCode());
assertEquals('00', metadata.getInternationalPrefix());
assertEquals('0', metadata.getNationalPrefix());
assertEquals(6, metadata.numberFormatCount());
assertEquals('9009', metadata.getNumberFormat(5).getLeadingDigits());
assertEquals('(\\d{3})(\\d{4})(\\d{4})',
metadata.getNumberFormat(5).getPattern());
assertEquals('$1 $2 $3', metadata.getNumberFormat(5).getFormat());
assertEquals(5, metadata.numberFormatCount());
assertEquals(1, metadata.getNumberFormat(4).leadingDigitsPatternCount());
assertEquals('900', metadata.getNumberFormat(4).getLeadingDigitsPattern(0));
assertEquals('(\\d{3})(\\d{3,4})(\\d{4})',
metadata.getNumberFormat(4).getPattern());
assertEquals('$1 $2 $3', metadata.getNumberFormat(4).getFormat());
assertEquals('(?:[24-6]\\d{2}|3[03-9]\\d|[789](?:[1-9]\\d|0[2-9]))\\d{3,8}',
metadata.getFixedLine().getNationalNumberPattern());
assertEquals('\\d{2,14}', metadata.getFixedLine().getPossibleNumberPattern());
@ -323,6 +324,14 @@ function testFormatDENumber() {
assertEquals('+49 9123 123',
phoneUtil.format(deNumber, PNF.INTERNATIONAL));
deNumber = new i18n.phonenumbers.PhoneNumber();
deNumber.setCountryCode(49);
deNumber.setNationalNumber(80212345);
assertEquals('08021 2345',
phoneUtil.format(deNumber, PNF.NATIONAL));
assertEquals('+49 8021 2345',
phoneUtil.format(deNumber, PNF.INTERNATIONAL));
deNumber = new i18n.phonenumbers.PhoneNumber();
deNumber.setCountryCode(49);
deNumber.setNationalNumber(1234);
@ -495,29 +504,27 @@ function testFormatOutOfCountryWithPreferredIntlPrefix() {
}
function testFormatWithCarrierCode() {
var PNF = i18n.phonenumbers.PhoneNumberFormat;
// We only support this for AR in our test metadata.
/** @type {i18n.phonenumbers.PhoneNumber} */
var arNumber = new i18n.phonenumbers.PhoneNumber();
arNumber.setCountryCode(54);
arNumber.setNationalNumber(91234125678);
assertEquals('01234 12-5678',
phoneUtil.format(arNumber,
i18n.phonenumbers.PhoneNumberFormat.NATIONAL));
phoneUtil.format(arNumber, PNF.NATIONAL));
// Test formatting with a carrier code.
assertEquals('01234 15 12-5678',
phoneUtil.formatNationalNumberWithCarrierCode(arNumber, '15'));
// Here the international rule is used, so no carrier code should be present.
assertEquals('+5491234125678',
phoneUtil.format(arNumber,
i18n.phonenumbers.PhoneNumberFormat.E164));
phoneUtil.format(arNumber, PNF.E164));
// We don't support this for the US so there should be no change.
/** @type {i18n.phonenumbers.PhoneNumber} */
var usNumber = new i18n.phonenumbers.PhoneNumber();
usNumber.setCountryCode(1);
usNumber.setNationalNumber(4241231234);
assertEquals('424 123 1234',
phoneUtil.format(usNumber,
i18n.phonenumbers.PhoneNumberFormat.NATIONAL));
phoneUtil.format(usNumber, PNF.NATIONAL));
assertEquals('424 123 1234',
phoneUtil.formatNationalNumberWithCarrierCode(usNumber, '15'));
}
@ -545,6 +552,23 @@ function testFormatByPattern() {
PNF.INTERNATIONAL,
newNumberFormats));
// $NP is set to '1' for the US. Here we check that for other NANPA countries
// the US rules are followed.
newNumFormat.setNationalPrefixFormattingRule('$NP ($FG)');
newNumFormat.setFormat('$1 $2-$3');
/** @type {i18n.phonenumbers.PhoneNumber} */
var bsNumber = new i18n.phonenumbers.PhoneNumber();
bsNumber.setCountryCode(1);
bsNumber.setNationalNumber(4168819999);
assertEquals('1 (416) 881-9999',
phoneUtil.formatByPattern(bsNumber,
PNF.NATIONAL,
newNumberFormats));
assertEquals('+1 416 881-9999',
phoneUtil.formatByPattern(bsNumber,
PNF.INTERNATIONAL,
newNumberFormats));
/** @type {i18n.phonenumbers.PhoneNumber} */
var itNumber = new i18n.phonenumbers.PhoneNumber();
itNumber.setCountryCode(39);
@ -1076,6 +1100,75 @@ function testIsNotPossibleNumber() {
assertFalse(phoneUtil.isPossibleNumberString('+44 300', 'GB'));
}
function testTruncateTooLongNumber() {
// US number 650-253-0000, but entered with one additional digit at the end.
/** @type {i18n.phonenumbers.PhoneNumber} */
var tooLongNumber = new i18n.phonenumbers.PhoneNumber();
tooLongNumber.setCountryCode(1);
tooLongNumber.setNationalNumber(65025300001);
/** @type {i18n.phonenumbers.PhoneNumber} */
var validNumber = new i18n.phonenumbers.PhoneNumber();
validNumber.setCountryCode(1);
validNumber.setNationalNumber(6502530000);
assertTrue(phoneUtil.truncateTooLongNumber(tooLongNumber));
assertTrue(validNumber.exactlySameAs(tooLongNumber));
// GB number 080 1234 5678, but entered with 4 extra digits at the end.
tooLongNumber = new i18n.phonenumbers.PhoneNumber();
tooLongNumber.setCountryCode(44);
tooLongNumber.setNationalNumber(80123456780123);
validNumber = new i18n.phonenumbers.PhoneNumber();
validNumber.setCountryCode(44);
validNumber.setNationalNumber(8012345678);
assertTrue(phoneUtil.truncateTooLongNumber(tooLongNumber));
assertTrue(validNumber.exactlySameAs(tooLongNumber));
// IT number 022 3456 7890, but entered with 3 extra digits at the end.
tooLongNumber = new i18n.phonenumbers.PhoneNumber();
tooLongNumber.setCountryCode(39);
tooLongNumber.setNationalNumber(2234567890123);
tooLongNumber.setItalianLeadingZero(true);
validNumber = new i18n.phonenumbers.PhoneNumber();
validNumber.setCountryCode(39);
validNumber.setNationalNumber(2234567890);
validNumber.setItalianLeadingZero(true);
assertTrue(phoneUtil.truncateTooLongNumber(tooLongNumber));
assertTrue(validNumber.exactlySameAs(tooLongNumber));
// Tests what happens when a valid number is passed in.
/** @type {i18n.phonenumbers.PhoneNumber} */
var validNumberCopy = new i18n.phonenumbers.PhoneNumber();
validNumberCopy.mergeFrom(validNumber);
assertTrue(phoneUtil.truncateTooLongNumber(validNumber));
// Tests the number is not modified.
assertTrue(validNumber.exactlySameAs(validNumberCopy));
// Tests what happens when a number with invalid prefix is passed in.
/** @type {i18n.phonenumbers.PhoneNumber} */
var numberWithInvalidPrefix = new i18n.phonenumbers.PhoneNumber();
// The test metadata says US numbers cannot have prefix 240.
numberWithInvalidPrefix.setCountryCode(1);
numberWithInvalidPrefix.setNationalNumber(2401234567);
/** @type {i18n.phonenumbers.PhoneNumber} */
var invalidNumberCopy = new i18n.phonenumbers.PhoneNumber();
invalidNumberCopy.mergeFrom(numberWithInvalidPrefix);
assertFalse(phoneUtil.truncateTooLongNumber(numberWithInvalidPrefix));
// Tests the number is not modified.
assertTrue(numberWithInvalidPrefix.exactlySameAs(invalidNumberCopy));
// Tests what happens when a too short number is passed in.
/** @type {i18n.phonenumbers.PhoneNumber} */
var tooShortNumber = new i18n.phonenumbers.PhoneNumber();
tooShortNumber.setCountryCode(1);
tooShortNumber.setNationalNumber(1234);
/** @type {i18n.phonenumbers.PhoneNumber} */
var tooShortNumberCopy = new i18n.phonenumbers.PhoneNumber();
tooShortNumberCopy.mergeFrom(tooShortNumber);
assertFalse(phoneUtil.truncateTooLongNumber(tooShortNumber));
// Tests the number is not modified.
assertTrue(tooShortNumber.exactlySameAs(tooShortNumberCopy));
}
function testIsViablePhoneNumber() {
var isViable = i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber;
// Only one or two digits before strange non-possible punctuation.
@ -1349,7 +1442,7 @@ function testMaybeExtractCountryCode() {
}
number = new i18n.phonenumbers.PhoneNumber();
try {
phoneNumber = '(1 610) 619 43 446';
phoneNumber = '(1 610) 619 43';
numberToFill = new goog.string.StringBuffer();
assertEquals('Should not have extracted a country code - invalid number ' +
'both before and after extraction of uncertain country code.',
@ -1412,6 +1505,8 @@ function testParseNationalNumber() {
var tollfreeNumber = new i18n.phonenumbers.PhoneNumber();
tollfreeNumber.setCountryCode(64);
tollfreeNumber.setNationalNumber(800332005);
assertTrue(tollfreeNumber.exactlySameAs(
phoneUtil.parse('0800 DDA 005', 'NZ')));
/** @type {i18n.phonenumbers.PhoneNumber} */
var premiumNumber = new i18n.phonenumbers.PhoneNumber();
premiumNumber.setCountryCode(64);
@ -1726,13 +1821,13 @@ function testParseExtensions() {
/** @type {i18n.phonenumbers.PhoneNumber} */
var nonExtnNumber = new i18n.phonenumbers.PhoneNumber();
nonExtnNumber.setCountryCode(1);
nonExtnNumber.setNationalNumber(180074935247);
nonExtnNumber.setNationalNumber(80074935247);
assertTrue(nonExtnNumber.exactlySameAs(
phoneUtil.parse('1800 six-flags', 'US')));
assertTrue(nonExtnNumber.exactlySameAs(
phoneUtil.parse('1800 SIX FLAGS', 'US')));
assertTrue(nonExtnNumber.exactlySameAs(
phoneUtil.parse('0~01 1800 7493 5247', 'PL')));
phoneUtil.parse('0~0 1800 7493 5247', 'PL')));
assertTrue(nonExtnNumber.exactlySameAs(
phoneUtil.parse('(1800) 7493.5247', 'US')));
@ -1740,10 +1835,10 @@ function testParseExtensions() {
/** @type {i18n.phonenumbers.PhoneNumber} */
var extnNumber = new i18n.phonenumbers.PhoneNumber();
extnNumber.setCountryCode(1);
extnNumber.setNationalNumber(180074935247);
extnNumber.setNationalNumber(80074935247);
extnNumber.setExtension('1234');
assertTrue(extnNumber.exactlySameAs(
phoneUtil.parse('0~01 1800 7493 5247 ~1234', 'PL')));
phoneUtil.parse('0~0 1800 7493 5247 ~1234', 'PL')));
// Verifying bug-fix where the last digit of a number was previously omitted
// if it was a 0 when extracting the extension. Also verifying a few different
@ -1807,6 +1902,9 @@ function testParseExtensions() {
usWithExtension.setExtension('910');
assertTrue(usWithExtension.exactlySameAs(
phoneUtil.parse('+1 (645) 123 1234-910#', 'US')));
// Retry with the same number in a slightly different format.
assertTrue(usWithExtension.exactlySameAs(
phoneUtil.parse('+1 (645) 123 1234 ext. 910#', 'US')));
}
function testParseAndKeepRaw() {
@ -1814,11 +1912,11 @@ function testParseAndKeepRaw() {
/** @type {i18n.phonenumbers.PhoneNumber} */
var alphaNumericNumber = new i18n.phonenumbers.PhoneNumber();
alphaNumericNumber.setCountryCode(1);
alphaNumericNumber.setNationalNumber(180074935247);
alphaNumericNumber.setRawInput('1800 six-flags');
alphaNumericNumber.setNationalNumber(80074935247);
alphaNumericNumber.setRawInput('800 six-flags');
alphaNumericNumber.setCountryCodeSource(CCS.FROM_DEFAULT_COUNTRY);
assertTrue(alphaNumericNumber.exactlySameAs(
phoneUtil.parseAndKeepRawInput('1800 six-flags', 'US')));
phoneUtil.parseAndKeepRawInput('800 six-flags', 'US')));
alphaNumericNumber.setCountryCode(1);
alphaNumericNumber.setNationalNumber(8007493524);


Loading…
Cancel
Save