diff --git a/javascript/i18n/phonenumbers/metadata.js b/javascript/i18n/phonenumbers/metadata.js index cbd053cc3..e23aecd23 100644 --- a/javascript/i18n/phonenumbers/metadata.js +++ b/javascript/i18n/phonenumbers/metadata.js @@ -1574,7 +1574,7 @@ i18n.phonenumbers.metadata.countryToMetadata = { ,,[,,"NA","NA"] ,,,[,,"NA","NA"] ,[,,"51\\d{7}","\\d{9}",,,"511234567"] -,,[,,"0(?:6[12]|8[05]|9[12])|112","\\d{3}",,,"112"] +,,[,,"0(?:[69][12]|8[05])|112","\\d{3}",,,"112"] ,[,,"NA","NA"] ] ,"ET":[,[,,"[1-59]\\d{8}","\\d{7,9}"] @@ -3039,7 +3039,7 @@ i18n.phonenumbers.metadata.countryToMetadata = { ,[,,"NA","NA"] ] ,"MK":[,[,,"[2-578]\\d{7}","\\d{8}"] -,[,,"(?:2(?:[23]\\d|5[124578]|6[01])|3(?:1[3-6]|2[2-6]|3[2-6]|4[2356])|4(?:[23][2-6]|4[3-6]|5[256]|6[25-8]|7[24-6]|8[4-6]))\\d{5}","\\d{6,8}",,,"22212345"] +,[,,"(?:2(?:[23]\\d|5[124578]|6[01])|3(?:1[3-6]|[23][2-6]|4[2356])|4(?:[23][2-6]|4[3-6]|5[256]|6[25-8]|7[24-6]|8[4-6]))\\d{5}","\\d{6,8}",,,"22212345"] ,[,,"7(?:[0-25-8]\\d|33)\\d{5}","\\d{8}",,,"72345678"] ,[,,"800\\d{5}","\\d{8}",,,"80012345"] ,[,,"5[02-9]\\d{6}","\\d{8}",,,"50012345"] @@ -3434,7 +3434,7 @@ i18n.phonenumbers.metadata.countryToMetadata = { ] ,"NG":[,[,,"[1-69]\\d{5,8}|[78]\\d{5,13}","\\d{5,14}"] ,[,,"[12]\\d{6,7}|9\\d{7}|(?:3\\d|4[023568]|5[02368]|6[02-469]|7[4-69]|8[2-9])\\d{6}|(?:4[47]|5[14579]|6[1578]|7[0-357])\\d{5,6}|(?:78|41)\\d{5}","\\d{5,9}",,,"12345678"] -,[,,"(?:1(?:7[34]\\d|8(?:04|[124579]\\d|8[0-3])|95\\d)|287[0-7]|3(?:18[1-8]|88[0-7]|9(?:8[5-9]|6[1-5])|)|4(?:28[0-2]|6(?:7[1-9]|8[02-47])|88[0-2])|5(?:2(?:7[7-9]|8\\d)|38[1-79]|48[0-7]|68[4-7])|6(?:2(?:7[7-9]|8\\d)|4(?:3[7-9]|6[129]|7[04-69]|8[129]|9[1-8])|58[0-2]|98[7-9])|7(?:38[0-7]|69[1-8]|78[2-4])|8(?:28[3-9]|38[0-2]|4(?:2[12]|3[147-9]|5[346]|7[4-9]|8[014-689])|58[1-8]|78[2-9]|88[5-7])|98[07]\\d)\\d{4}|(?:70(?:[3-9]\\d|2[1-9])|8(?:0[2-9]|1[0235689])\\d)\\d{6}","\\d{8,10}",,,"8021234567"] +,[,,"(?:1(?:7[34]\\d|8(?:04|[124579]\\d|8[0-3])|95\\d)|287[0-7]|3(?:18[1-8]|88[0-7]|9(?:8[5-9]|6[1-5])|)|4(?:28[0-2]|6(?:7[1-9]|8[02-47])|88[0-2])|5(?:2(?:7[7-9]|8\\d)|38[1-79]|48[0-7]|68[4-7])|6(?:2(?:7[7-9]|8\\d)|4(?:3[7-9]|[68][129]|7[04-69]|9[1-8])|58[0-2]|98[7-9])|7(?:38[0-7]|69[1-8]|78[2-4])|8(?:28[3-9]|38[0-2]|4(?:2[12]|3[147-9]|5[346]|7[4-9]|8[014-689])|58[1-8]|78[2-9]|88[5-7])|98[07]\\d)\\d{4}|(?:70(?:[3-9]\\d|2[1-9])|8(?:0[2-9]|1[0235689])\\d)\\d{6}","\\d{8,10}",,,"8021234567"] ,[,,"800\\d{7,11}","\\d{10,14}",,,"80017591759"] ,[,,"NA","NA"] ,[,,"NA","NA"] diff --git a/javascript/i18n/phonenumbers/metadatalite.js b/javascript/i18n/phonenumbers/metadatalite.js index 52ed44636..38a155bd7 100644 --- a/javascript/i18n/phonenumbers/metadatalite.js +++ b/javascript/i18n/phonenumbers/metadatalite.js @@ -1574,7 +1574,7 @@ i18n.phonenumbers.metadata.countryToMetadata = { ,,[,,"NA","NA"] ,,,[,,"NA","NA"] ,[,,"51\\d{7}","\\d{9}"] -,,[,,"0(?:6[12]|8[05]|9[12])|112","\\d{3}"] +,,[,,"0(?:[69][12]|8[05])|112","\\d{3}"] ,[,,"NA","NA"] ] ,"ET":[,[,,"[1-59]\\d{8}","\\d{7,9}"] @@ -3039,7 +3039,7 @@ i18n.phonenumbers.metadata.countryToMetadata = { ,[,,"NA","NA"] ] ,"MK":[,[,,"[2-578]\\d{7}","\\d{8}"] -,[,,"(?:2(?:[23]\\d|5[124578]|6[01])|3(?:1[3-6]|2[2-6]|3[2-6]|4[2356])|4(?:[23][2-6]|4[3-6]|5[256]|6[25-8]|7[24-6]|8[4-6]))\\d{5}","\\d{6,8}"] +,[,,"(?:2(?:[23]\\d|5[124578]|6[01])|3(?:1[3-6]|[23][2-6]|4[2356])|4(?:[23][2-6]|4[3-6]|5[256]|6[25-8]|7[24-6]|8[4-6]))\\d{5}","\\d{6,8}"] ,[,,"7(?:[0-25-8]\\d|33)\\d{5}","\\d{8}"] ,[,,"800\\d{5}","\\d{8}"] ,[,,"5[02-9]\\d{6}","\\d{8}"] @@ -3434,7 +3434,7 @@ i18n.phonenumbers.metadata.countryToMetadata = { ] ,"NG":[,[,,"[1-69]\\d{5,8}|[78]\\d{5,13}","\\d{5,14}"] ,[,,"[12]\\d{6,7}|9\\d{7}|(?:3\\d|4[023568]|5[02368]|6[02-469]|7[4-69]|8[2-9])\\d{6}|(?:4[47]|5[14579]|6[1578]|7[0-357])\\d{5,6}|(?:78|41)\\d{5}","\\d{5,9}"] -,[,,"(?:1(?:7[34]\\d|8(?:04|[124579]\\d|8[0-3])|95\\d)|287[0-7]|3(?:18[1-8]|88[0-7]|9(?:8[5-9]|6[1-5])|)|4(?:28[0-2]|6(?:7[1-9]|8[02-47])|88[0-2])|5(?:2(?:7[7-9]|8\\d)|38[1-79]|48[0-7]|68[4-7])|6(?:2(?:7[7-9]|8\\d)|4(?:3[7-9]|6[129]|7[04-69]|8[129]|9[1-8])|58[0-2]|98[7-9])|7(?:38[0-7]|69[1-8]|78[2-4])|8(?:28[3-9]|38[0-2]|4(?:2[12]|3[147-9]|5[346]|7[4-9]|8[014-689])|58[1-8]|78[2-9]|88[5-7])|98[07]\\d)\\d{4}|(?:70(?:[3-9]\\d|2[1-9])|8(?:0[2-9]|1[0235689])\\d)\\d{6}","\\d{8,10}"] +,[,,"(?:1(?:7[34]\\d|8(?:04|[124579]\\d|8[0-3])|95\\d)|287[0-7]|3(?:18[1-8]|88[0-7]|9(?:8[5-9]|6[1-5])|)|4(?:28[0-2]|6(?:7[1-9]|8[02-47])|88[0-2])|5(?:2(?:7[7-9]|8\\d)|38[1-79]|48[0-7]|68[4-7])|6(?:2(?:7[7-9]|8\\d)|4(?:3[7-9]|[68][129]|7[04-69]|9[1-8])|58[0-2]|98[7-9])|7(?:38[0-7]|69[1-8]|78[2-4])|8(?:28[3-9]|38[0-2]|4(?:2[12]|3[147-9]|5[346]|7[4-9]|8[014-689])|58[1-8]|78[2-9]|88[5-7])|98[07]\\d)\\d{4}|(?:70(?:[3-9]\\d|2[1-9])|8(?:0[2-9]|1[0235689])\\d)\\d{6}","\\d{8,10}"] ,[,,"800\\d{7,11}","\\d{10,14}"] ,[,,"NA","NA"] ,[,,"NA","NA"] diff --git a/javascript/i18n/phonenumbers/phonenumberutil.js b/javascript/i18n/phonenumbers/phonenumberutil.js index b4a41bce7..38b16a0c8 100644 --- a/javascript/i18n/phonenumbers/phonenumberutil.js +++ b/javascript/i18n/phonenumbers/phonenumberutil.js @@ -658,14 +658,36 @@ i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_ = * used as a placeholder for carrier codes, for example in Brazilian phone * numbers. We also allow multiple '+' characters at the start. * Corresponds to the following: + * [digits]{minLengthNsn}| * plus_sign* * (([punctuation]|[star])*[digits]){3,}([punctuation]|[star]|[digits]|[alpha])* + * + * The first reg-ex is to allow short numbers (two digits long) to be parsed if + * they are entered as "15" etc, but only if there is no punctuation in them. + * The second expression restricts the number of digits to three or more, but + * then allows them to be in international form, and to have alpha-characters + * and punctuation. We split up the two reg-exes here and combine them when + * creating the reg-ex VALID_PHONE_NUMBER_PATTERN_ itself so we can prefix it + * with ^ and append $ to each branch. + * * Note VALID_PUNCTUATION starts with a -, so must be the first in the range. * * @const * @type {string} * @private */ +i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_PHONE_NUMBER_PATTERN_ = + '[' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{' + + i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_ + '}'; + + +/** + * See MIN_LENGTH_PHONE_NUMBER_PATTERN_ for a full description of this reg-exp. + * + * @const + * @type {string} + * @private + */ i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ = '[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']*(?:[' + i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION + @@ -755,10 +777,13 @@ i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_ = * @private */ i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_PATTERN_ = - new RegExp('^' + i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ + - '(?:' + - i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERNS_FOR_PARSING_ + - ')?' + '$', 'i'); + new RegExp( + '^' + + i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_PHONE_NUMBER_PATTERN_ + + '$|' + + '^' + i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ + + '(?:' + i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERNS_FOR_PARSING_ + + ')?' + '$', 'i'); /** diff --git a/javascript/i18n/phonenumbers/phonenumberutil_test.js b/javascript/i18n/phonenumbers/phonenumberutil_test.js index 8c6023cd7..a81302504 100644 --- a/javascript/i18n/phonenumbers/phonenumberutil_test.js +++ b/javascript/i18n/phonenumbers/phonenumberutil_test.js @@ -1698,16 +1698,20 @@ function testTruncateTooLongNumber() { function testIsViablePhoneNumber() { var isViable = i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber; + assertFalse(isViable('1')); // Only one or two digits before strange non-possible punctuation. - assertFalse(isViable('12. March')); assertFalse(isViable('1+1+1')); assertFalse(isViable('80+0')); - assertFalse(isViable('00')); - // Three digits is viable. + // Two digits is viable. + assertTrue(isViable('00')); assertTrue(isViable('111')); // Alpha numbers. assertTrue(isViable('0800-4-pizza')); assertTrue(isViable('0800-4-PIZZA')); + // We need at least three digits before any alpha characters. + assertFalse(isViable('08-PIZZA')); + assertFalse(isViable('8-PIZZA')); + assertFalse(isViable('12. March')); } function testIsViablePhoneNumberNonAscii() { @@ -2113,6 +2117,12 @@ function testParseNationalNumber() { // make sure we can parse the output we produce when formatting the number. assertTrue( JP_STAR_NUMBER.equals(phoneUtil.parse('+81 *2345', RegionCode.JP))); + + /** @type {i18n.phonenumbers.PhoneNumber} */ + var shortNumber = new i18n.phonenumbers.PhoneNumber(); + shortNumber.setCountryCode(64); + shortNumber.setNationalNumber(12); + assertTrue(shortNumber.equals(phoneUtil.parse('12', RegionCode.NZ))); } function testParseNumberWithAlphaCharacters() { @@ -2345,6 +2355,39 @@ function testFailedParseOnInvalidNumbers() { i18n.phonenumbers.Error.NOT_A_NUMBER, e); } + try { + sentencePhoneNumber = '1 Still not a number'; + phoneUtil.parse(sentencePhoneNumber, RegionCode.NZ); + fail('This should not parse without throwing an exception ' + + sentencePhoneNumber); + } catch (e) { + // Expected this exception. + assertEquals('Wrong error type stored in exception.', + i18n.phonenumbers.Error.NOT_A_NUMBER, + e); + } + try { + sentencePhoneNumber = '1 MICROSOFT'; + phoneUtil.parse(sentencePhoneNumber, RegionCode.NZ); + fail('This should not parse without throwing an exception ' + + sentencePhoneNumber); + } catch (e) { + // Expected this exception. + assertEquals('Wrong error type stored in exception.', + i18n.phonenumbers.Error.NOT_A_NUMBER, + e); + } + try { + sentencePhoneNumber = '12 MICROSOFT'; + phoneUtil.parse(sentencePhoneNumber, RegionCode.NZ); + fail('This should not parse without throwing an exception ' + + sentencePhoneNumber); + } catch (e) { + // Expected this exception. + assertEquals('Wrong error type stored in exception.', + i18n.phonenumbers.Error.NOT_A_NUMBER, + e); + } try { /** @type {string} */ var tooLongPhoneNumber = '01495 72553301873 810104'; @@ -2440,7 +2483,6 @@ function testFailedParseOnInvalidNumbers() { e); } try { - /** @type {string} */ someNumber = '123 456 7890'; phoneUtil.parse(someNumber, RegionCode.CS); fail('Deprecated region code not allowed: should fail.'); @@ -2900,7 +2942,7 @@ function testIsNumberMatchNonMatches() { // Invalid numbers that can't be parsed. assertEquals(i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER, - phoneUtil.isNumberMatch('43', '3 331 6043')); + phoneUtil.isNumberMatch('4', '3 331 6043')); assertEquals(i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER, phoneUtil.isNumberMatch('+43', '+64 3 331 6005')); assertEquals(i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER, @@ -3028,7 +3070,10 @@ function testIsAlphaNumber() { assertTrue(phoneUtil.isAlphaNumber('1800 six-flags')); assertTrue(phoneUtil.isAlphaNumber('1800 six-flags ext. 1234')); assertTrue(phoneUtil.isAlphaNumber('+800 six-flags')); + assertTrue(phoneUtil.isAlphaNumber('180 six-flags')); assertFalse(phoneUtil.isAlphaNumber('1800 123-1234')); + assertFalse(phoneUtil.isAlphaNumber('1 six-flags')); + assertFalse(phoneUtil.isAlphaNumber('18 six-flags')); assertFalse(phoneUtil.isAlphaNumber('1800 123-1234 extension: 1234')); assertFalse(phoneUtil.isAlphaNumber('+800 1234-1234')); }