diff --git a/java/resources/com/google/i18n/phonenumbers/src/PhoneNumberMetaData.xml b/java/resources/com/google/i18n/phonenumbers/src/PhoneNumberMetaData.xml
index b83058eba..0e72c87b8 100644
--- a/java/resources/com/google/i18n/phonenumbers/src/PhoneNumberMetaData.xml
+++ b/java/resources/com/google/i18n/phonenumbers/src/PhoneNumberMetaData.xml
@@ -237,8 +237,60 @@
+
+ nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
+
+
+ $1 $2 $3
+ $1 $2 $3
+ $1 $2 $3
+ $1 $2
+ $1 $2
+ $1 $2
+ $1 $2
+
+
+ [2-57]\d{7}|6\d{8}|8\d{5,7}|9\d{5}
+ \d{5,9}
+
+
+ (?:2(?:[168][1-9]|[247]\d|9[1-7])|3(?:1[1-3]|[2-6]\d|[79][1-8]|8[1-9])|4\d{2}|5(?:1[1-4]|[2-578]\d|6[1-5]|9[1-7])|8(?:[19][1-5]|[2-6]\d|[78][1-7]))\d{5}
+ \d{5,8}
+ 22345678
+
+
+ 6[6-9]\d{7}
+ \d{9}
+ 661234567
+
+
+ 800\d{4}
+ \d{7}
+ 8001234
+
+
+
+ 900\d{3}
+ \d{6}
+ 900123
+
+
+ 808\d{3}
+ \d{6}
+ 808123
+
+
+ 700\d{5}
+ \d{8}
+ 70012345
+
@@ -251,8 +303,24 @@
-
+
+
+
+ $1 $2 $3
+
+
+ [29]\d{8}
+ \d{9}
+
+
+ 2\d(?:[26-9]\d|\d[26-9])\d{5}
+ 222123456
+
+
+
+ 9[1-3]\d{7}
+ 923123456
+
@@ -514,11 +582,11 @@
\d{8,9}
- (?:1(?:(?:2[3-5]|36|8\d|9)\d|02|1[0-589]|3[358]|4[013-79]|5[0-479]|6[0236-9]|7[0-24-8])|2(?:16|2\d|3[0-24]|4[1468]|55|6[56]|79))\d{5}
+ (?:1(?:(?:[28]\d|36|9)\d|02|1[0-589]|3[358]|4[013-79]|5[0-479]|6[0236-9]|7[0-24-8])|2(?:16|2\d|3[0-24]|4[1468]|55|6[56]|79))\d{5}
123123456
- (?:40|5[015]|7[07])\d{7}|60540\d{4}
+ (?:4[04]|5[015]|60|7[07])\d{7}
\d{9}
401234567
@@ -617,7 +685,26 @@
+
+
+
+ $1 $2 $3 $4
+
+
+ [2457]\d{7}
+ \d{8}
+
+
+
+ (?:20(?:49|5[23]|9[016-9])|40(?:4[569]|55|7[0179])|50[34]\d)\d{4}
+ 20491234
+
+
+ 7(?:[0168]\d|2[0-4]|4[01]|5[01346-9])\d{5}
+ 70123456
+
@@ -665,11 +752,70 @@
+
+
+ $1 $2 $3 $4
+
+
+ [27]\d{7}
+ \d{8}
+
+
+ 22(?:2[0-7]|[3-5]0)\d{4}
+ 22201234
+
+
+
+
+ (?:2955|7(?:9(?:5[6-9]|[19]\d)|(?:6[269]|77|8\d)\d))\d{4}
+ 79561234
+
+
+
+ $1 $2 $3 $4
+
+
+
+ [289]\d{7}|7\d{3}
+ \d{4,8}
+
+
+
+ 2(?:02|1[037]|2[45]|3[68])\d{5}
+ \d{8}
+ 20211234
+
+
+
+ 9(?:0[069]|[35][0-2457-9]|7[014-9])\d{5}
+ \d{8}
+ 90011234
+
+
+ 7[3-5]\d{2}
+ \d{4}
+ 7312
+
+
+
+ 857[58]\d{4}
+ \d{8}
+ 85751234
+
@@ -685,11 +831,11 @@
\d{7,10}
- 441(?:2(?:02|23|[3479]\d)|[46]\d{2}|5(?:40|89)|824)\d{4}
+ 441(?:2(?:02|23|61|[3479]\d)|[46]\d{2}|5(?:4\d|60|89)|824)\d{4}
4412345678
- 441(?:[37]\d{2}|5(?:[0-3]\d|9[09]))\d{4}
+ 441(?:[37]\d|5[0-39])\d{5}
\d{10}
4413701234
@@ -906,11 +1052,50 @@
+
+
+ $1 $2 $3 $4
+
+
+ [278]\d{7}
+ \d{8}
+
+
+ 2[12]\d{6}
+ 21612345
+
+
+ 7[0257]\d{6}
+ 70012345
+
+
+ 8776\d{4}
+ 87761234
+
+
+
+ $1 $2
+
+
+ [24-68]\d{6}
+ \d{7}
+
+
+
+ (?:2[1-589]|8\d)\d{5}
+ 2123456
+
+
+ [4-6]\d{6}
+ 5012345
+
@@ -1158,11 +1343,58 @@
+
+
+ $1 $2 $3
+
+
+ [29]\d{6}
+ \d{7}
+
+
+ 2(?:2[1-7]|3[0-8]|4[12]|5[1256]|6\d|7[1-3]|8[1-5])\d{4}
+ 2211234
+
+
+ 9[189]\d{5}
+ 9911234
+
+
+
+
+ $1 $2
+
+
+ [27-9]\d{7}
+ \d{8}
+
+
+ 2[2-6]\d{6}
+ 22345678
+
+
+
+ 7777\d{4}|9(?:[69]\d|7[67])\d{5}
+ 96123456
+
+
+ 8000\d{4}
+ 80001234
+
+
+ 9009\d{4}
+ 90091234
+
+
+ 700\d{5}
+ 70012345
+
@@ -1273,7 +1505,30 @@
+
+
+
+ $1 $2 $3
+
+
+ [2-8]\d{5}
+ \d{6}
+
+
+
+ (?:25|3[0-6]|42)\d{4}
+ 251234
+
+
+
+ (?:[5-7]\d|8[0-7])\d{4}
+ 601234
+
@@ -1454,8 +1709,27 @@
+
+ nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
+
+ $1 $2 $3
+
+
+ [178]\d{6}
+ \d{6,7}
+
+
+ 1(?:1[12568]|20|40|55|6[146])\d{4}|8\d{6}
+ 8370362
+
+
+
+ 17[1-3]\d{4}|7\d{6}
+ \d{7}
+ 7123456
+
@@ -1495,8 +1769,27 @@
+
+ nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
+
+ $1 $2 $3
+
+
+ [1-59]\d{8}
+ \d{7,9}
+
+
+ (?:11(?:1(?:1[124]|2[2-57]|3[1-5]|5[5-8]|8[6-8])|2(?:13|3[6-8]|5[89]|7[05-9]|8[2-6])|3(?:2[01]|3[0-289]|4[1289]|7[1-4]|87)|4(?:1[69]|3[2-49]|4[0-23]|6[5-8])|5(?:1[57]|44|5[0-4])|6(?:18|2[69]|4[5-7]|5[1-5]|6[0-59]|8[015-8]))|2(?:2(?:11[1-9]|22[0-7]|33\d|44[1467]|66[1-68])|5(?:11[124-6]|33[2-8]|44[1467]|55[14]|66[1-3679]|77[124-79]|880))|3(?:3(?:11[0-46-8]|22[0-6]|33[0134689]|44[04]|55[0-6]|66[01467])|4(?:44[0-8]|55[0-69]|66[0-3]|77[1-5]))|4(?:6(?:22[0-24-7]|33[1-5]|44[13-69]|55[14-689]|660|88[1-4])|7(?:11[1-9]|22[1-9]|33[13-7]|44[13-6]|55[1-689]))|5(?:7(?:227|55[05]|(?:66|77)[14-8])|8(?:11[149]|22[013-79]|33[0-68]|44[013-8]|550|66[1-5]|77\d)))\d{4}
+ 111112345
+
+
+
+ 91(?:1(?:[146]\d|2[0-5]|3[4-6]|50|7[2-6]|8[46-9])|31\d|4(?:3[0-2489]|7[0-3])|5(?:3[23]|7[3-5])|6(?:58|8[23])|7(?:5[57]|8[01])|8(?:3[45]|7[67]))\d{4}
+ \d{9}
+ 911123456
+
@@ -1593,7 +1886,35 @@
+
+
+ $1 $2 $3
+ $1 $2 $3 $4
+
+
+ [4-9]\d{5}|0\d{7}
+ \d{6,8}
+
+
+ (?:4(?:[04-8]\d|2[04])|(?:5[04-689]|6[024-9]|7\d|8[236]|9[02368])\d)\d{3}
+ \d{6}
+ 441234
+
+
+
+
+ 0(?:5(?:0[89]|3[0-4]|8[0-26]|9[238])|6(?:0[3-7]|1[01]|2[0-7]|6[0-589]|71|83|9[57])|7(?:1[2-5]|2[89]|3[35-9]|4[01]|5[0-347-9]|[67]\d|8[457-9]|9[0146]))\d{4}
+ \d{8}
+ 06031234
+
@@ -1750,6 +2071,7 @@
+
@@ -1758,7 +2080,7 @@
$1 $2
$1 $2 $3
- $1 $2 $3
+ $1 $2 $3
$1 $2 $3
@@ -1774,7 +2096,7 @@
251234
- 2(?:755\d{4}|(?:4|08)\d{6}|[368]\d{7})|54\d{7}
+ 2(?:755\d{4}|(?:4\d?|08)\d{6}|[368]\d{7})|54\d{7}
\d{8,9}
27551234
@@ -1790,7 +2112,23 @@
+
+
+ $1 $2
+
+
+ [3-9]\d{6}
+ \d{7}
+
+
+ (4(?:[23]\d{2}|4(?:1[024679]|[6-9]\d))|5(?:54[0-7]|6(?:[67]\d)|7(?:1[04]|2[035]|3[58]|48))|8\d{3})\d{3}
+ 5661234
+
+
+ [3679]\d{6}
+ 3012345
+
@@ -1803,7 +2141,25 @@
+
+
+
+ $1 $2 $3
+
+
+ [0256]\d{5}
+ \d{6}
+
+
+ 0[46-9]\d{4}
+ 041234
+
+
+ [256]\d{5}
+ 212345
+
@@ -1884,7 +2240,23 @@
+
+
+ $1 $2
+
+
+ [3567]\d{6}
+ \d{7}
+
+
+ 3(?:2[0125]|3[1245]|4[12]|5[1-4]|70|9[1-467])\d{4}
+ 3201234
+
+
+ [5-7]\d{6}
+ 5012345
+
@@ -2086,12 +2458,13 @@
+
- $1 $2 $3
+ $1 $2 $3
$1 $2
$1 $2
@@ -2126,7 +2499,7 @@
people dial, allowing them to easily dial Northern Ireland. We support
these numbers here, although technically they are numbers for the UK.
-->
- (?:2[24-9]|4(?:0[24]|7)|5(?:0[45]|8)|6[237-9]|9[3-9])\d{5}|(?:45|[569]1|818)\d{6}|(?:1|4[12469]|5[3679]|6[56]|7[14]|9[04])\d{7}|21\d{6,7}|(?:23|4[34]|52|64)\d{5,7}|48\d{8}
+ 1\d{7,8}|(?:2[24-9]|4(?:0[24]|7)|5(?:0[45]|8)|6[237-9]|9[3-9])\d{5}|(?:45|[569]1|818)\d{6}|(?:4[12469]|5[3679]|6[56]|7[14]|9[04])\d{7}|21\d{6,7}|(?:23|4[34]|52|64)\d{5,7}|48\d{8}
\d{5,10}
2212345
@@ -2141,7 +2514,7 @@
1800123456
- 15(?:1[2-9]|[2-9]0|59)\d{6}
+ 15(?:1[2-9]|[2-8]0|59|9[089])\d{6}
\d{10}
1520123456
@@ -2690,7 +3063,25 @@
+
+
+ $1 $2 $3
+
+
+ [37]\d{6}
+ \d{7}
+
+
+
+ 7(?:6[0-37-9]|7[0-57-9])\d{4}
+ 7712345
+
+
+ 3[23]\d{5}
+ 3212345
+
@@ -2987,8 +3378,32 @@
+
+ nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
+
+
+ $1 $2 $3
+ $1 $2 $3
+
+
+ (?:[27]\d|[4-6])\d{6}
+ \d{7,8}
+
+
+ 2\d{7}
+ \d{8}
+ 21234567
+
+
+
+ (?:4[67]|5\d|7\d{2}|6[4-8])\d{5}
+ 4612345
+
@@ -3079,8 +3494,36 @@
+
+ nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
+
+ $1 $2 $3
+ $1 $2 $3
+ $1 $2
+
+
+ [256-9]\d{7}
+ \d{8}
+
+
+ (?:2(?:1[0569]|2\d|3[015-7]|4[1-46-9]|5[0-24689]|6[2-589]|7[1-37]|9[1347-9])|5(?:33|5[257]))\d{5}
+ \d{5,8}
+ 22212345
+
+
+ (?:6(?:50|7[12]|8[0-7]|9\d)|7(?:80|9\d))\d{5}
+ 65012345
+
+
+ 800\d{5}
+ 80012345
+
+
+ 900\d{5}
+ 90012345
+
@@ -3089,8 +3532,31 @@
+
+ nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
+
+ $1 $2 $3 $4
+
+
+ [23]\d{8}
+ \d{7,9}
+
+
+
+ 2(?:0(?:(?:2\d|4[47]|5[3467]|6[279]|8[268]|9[245])\d|7(?:2[29]|[35]\d))|210\d)\d{4}
+ 202123456
+
+
+
+ 3[02-4]\d{7}
+ \d{9}
+ 301234567
+
@@ -3099,13 +3565,73 @@
+
+ nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
+
+
+ $1 $2 $3
+ $1 $2 $3
+ $1 $2 $3 $4
+
+
+ [2-578]\d{7}
+ \d{8}
+
+
+ (?:2\d|3[1-4]|4[2-8])\d{6}
+ \d{6,8}
+ 22212345
+
+
+ 7\d{7}
+ 72345678
+
+
+ 800\d{5}
+ 80012345
+
+
+ 5[02-9]\d{6}
+ 50012345
+
+
+ 8(?:0[1-9]|[1-9]\d)\d{5}
+ 80123456
+
+
+
+
+ $1 $2 $3 $4
+
+
+ [246-8]\d{7}
+ \d{8}
+
+
+
+ (?:2(?:0(?:2[0-589]|7[027-9])|1(?:2[5-7]|[3-9]\d))|442\d)\d{4}
+ 20212345
+
+
+ (?:6(?:[569]\d)|7(?:[359][0-4]|4[014-7]|6\d|8[1-9]))\d{5}
+ 65012345
+
+
+
+ 800\d{5}
+ 80012345
+
@@ -3230,8 +3756,24 @@
-
+
+
+
+
+ $1 $2 $3
+
+
+ [2-7]\d{6}
+ \d{7}
+
+
+ 5(?:1[035]|2[0-69]|3[0348]|4[468]|5[02-467]|6[39]|7[4-69])\d{4}
+ 5131234
+
+
+ (?:[23][0-4]|4[3-5]|6\d|7[0-7])\d{5}
+ 3123456
+
@@ -3286,12 +3828,15 @@
(?:2(?:[034789]\d|1[0-8]|2[0-79])|4(?:[013-8]\d|2[4-7])|[56]\d{2}|8(?:14|3[129]))\d{4}
+ 2012345
(?:25\d|4(?:2[12389]|9\d)|7\d{2}|87[15-7]|9[13-8]\d)\d{4}
+ 2512345
80[012]\d{4}
+ 8001234
30\d{5}
+ 3012345
@@ -3308,7 +3854,37 @@
-
+
+
+
+
+ $1 $2 $3
+ $1 $2 $3
+ $1 $2 $3
+ $1 $2 $3
+
+
+
+ (?:[13-5]|[27]\d{2}|[89](?:\d{2})?)\d{6}
+ \d{7,9}
+
+
+ (?:1[2-9]|21\d{2})\d{5}
+ 1234567
+
+
+ (?:[3-5]|77|8(?:8\d)?|9(?:9\d)?)\d{6}
+ 991234567
+
@@ -3433,13 +4009,81 @@
-
+
+
+
+ $1 $2 $3
+ $1 $2 $3
+ $1 $2 $3
+
+
+ [28]\d{7,8}
+ \d{8,9}
+
+
+ 2(?:[1346]\d|5[0-2]|[78][12]|93)\d{5}
+ \d{8}
+ 21123456
+
+
+ 8[24]\d{7}
+ \d{9}
+ 821234567
+
+
+
+ 800\d{6}
+ \d{9}
+ 800123456
+
+
+ nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
+
+ $1 $2 $3
+
+ $1 $2
+ $1 $2 $3
+
+ $1 $2
+ $1 $2
+ $1 $2
+ $1 $2 $3
+
+
+ [68]\d{5,9}
+ \d{4,10}
+
+
+ 6(?:1(?:[136]|2\d?)\d|2(?:[25]\d?|[134678])\d|3(?:2\d{0,3}|4\d{1,2}|[135-8]\d?)|4(?:[13-8]\d|2\d{1,2})|(?:5(?:[16-7]\d|[3-58]\d?|2\d{1,2}))|6\d{0,4}|7\d{0,3})\d{4}
+ 612012345
+
+
+ 8(?:1(?:1[0-2]|[23]\d|50)|5\d{2})\d{5}
+ \d{9}
+ 811012345
+
+
+ 88\d{6}
+ \d{8}
+ 88123456
+
@@ -3756,23 +4400,28 @@
- $1 $2
- $1 $2 $3
+ $1 $2
+ $1 $2 $3
[1-9]\d{6,7}
\d{7,8}
- (?:3\d|47|[56]4|73|85|9[78])\d{5}
+
+ (?:3\d{2}|4[257]\d|5[34]\d|6[24]9|85[02-46-9]|9[78]\d)\d{4}
\d{7}
3123456
- (?:6[357-9]|7[126]\d)\d{5}
+
+ (?:68|7(?:[126]\d|3[34689]))\d{5}
\d{7,8}
- 6345678
+ 6812345
180\d{4}
@@ -4187,15 +4836,19 @@
25\d{7}
+ 250123456
7[258]\d{7}
+ 720123456
800\d{6}
+ 800123456
900\d{6}
+ 900123456
@@ -4474,8 +5127,23 @@
-
+
+
+
+ $1 $2
+
+
+ [29]\d{6}
+ \d{7}
+
+
+ 22\d{5}
+ 2221234
+
+
+ 9[89]\d{5}
+ 9812345
+
@@ -4511,7 +5179,32 @@
+
+
+
+ [2-7]\d{6,7}
+ \d{7,8}
+
+
+ $1 $2
+ $1 $2
+
+
+
+ 2?(?:2(?:0[07]|[13]7|2[57])|3(?:0[34]|[1278]3|3[23]|[46][34])|(?:40[4-69]|16|2[12]|3[57]|[4578]2|67)|5(?:0[5-7]|1[6-9]|[23][78]|48|5[01]))\d{4}
+ 2171234
+
+
+
+ (?:6|7[67])\d{6}
+ 6012345
+
@@ -4549,7 +5242,29 @@
-
+
+
+
+
+ $1 $2 $3
+
+
+ [2369]\d{6}
+ \d{7}
+
+
+ 2(?:5[0-4]|6[89])\d{4}
+ 2511234
+
+
+
+ (?:3[0-7]|6[27]|9\d)\d{5}
+ 6201234
+
@@ -4558,7 +5273,24 @@
+
+
+ $1 $2 $3
+
+
+ [02-9]\d{6}
+ \d{7}
+
+
+ (?:2[2-7]|3[23]|44|55|66|77)\d{5}
+ 2212345
+
+
+
+ (?:0[1-9]|7[56]|8[1-7]|9\d)\d{5}
+ 0112345
+
@@ -5069,6 +5801,10 @@
$1 $2 $3
$1 $2 $3
+ $1 $2
+ $1 $2
$1 $2 $3
$1 $2
- [1-9]\d{6,9}
+ 8\d{5,8}|[1-79]\d{7,9}
\d{7,10}
- [2-8]\d{6,9}
+ (?:2(?:[025-79]|1[0189]|[348][01])|3(?:[0136-9]|[25][01])|[48]\d|5(?:[01][01]|[2-9])|6(?:[0-46-8]|5[01])|7(?:[02-79]|[18][01]))\d{7}|(?:80|69[3-5])\d{5}
\d{7,10}
- 2123456
+ 2101234567
- (?:9[0-8]|1(?:2[1-369]|6[46-9]|99))\d{7}
+ (?:9[0-8]|1(?:2\d|6[46-9]|99))\d{7}
\d{9,10}
912345678
@@ -5182,8 +5918,32 @@
+
+ nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
+
+
+ [268]\d{8}
+ \d{9}
+
+
+ 2696[0-4]\d{4}
+ 269601234
+
+
+ 639\d{6}
+ 639123456
+
+
+
+ 80\d{7}
+ 801234567
+
@@ -5225,9 +5985,25 @@
-
+
+
+ nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
+
+ $1 $2
+
+
+ [29]\d{8}
+ \d{9}
+
+
+ 21[1-8]\d{6}
+ 211234567
+
+
+ 9(?:55|66|7[7-9])\d{6}
+ 955123456
+
diff --git a/java/resources/com/google/i18n/phonenumbers/src/generated_files/PhoneNumberMetadataProto b/java/resources/com/google/i18n/phonenumbers/src/generated_files/PhoneNumberMetadataProto
index 1c6227f1e..2cad06486 100644
Binary files a/java/resources/com/google/i18n/phonenumbers/src/generated_files/PhoneNumberMetadataProto and b/java/resources/com/google/i18n/phonenumbers/src/generated_files/PhoneNumberMetadataProto differ
diff --git a/java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java b/java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java
index 4e0935726..12bb94681 100644
--- a/java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java
+++ b/java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java
@@ -16,8 +16,8 @@
package com.google.i18n.phonenumbers;
-import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
import com.google.i18n.phonenumbers.Phonemetadata.NumberFormat;
+import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
import java.util.ArrayList;
import java.util.List;
@@ -42,10 +42,11 @@ public class AsYouTypeFormatter {
private String formattingTemplate;
private StringBuffer accruedInput;
private StringBuffer accruedInputWithoutFormatting;
- private boolean ableToFormat;
+ private boolean ableToFormat = true;
+ private boolean isInternationalFormatting = false;
private final PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
private String defaultCountry;
- private PhoneMetadata defaultMetaData;
+ private Phonemetadata.PhoneMetadata defaultMetaData;
private PhoneMetadata currentMetaData;
// The digits that have not been entered yet will be represented by a \u2008, the punctuation
@@ -69,7 +70,6 @@ public class AsYouTypeFormatter {
accruedInputWithoutFormatting = new StringBuffer();
currentOutput = new StringBuffer();
prefixBeforeNationalNumber = new StringBuffer();
- ableToFormat = true;
nationalNumber = new StringBuffer();
defaultCountry = regionCode;
initializeCountrySpecificInfo(defaultCountry);
@@ -101,7 +101,10 @@ public class AsYouTypeFormatter {
private List getAvailableFormats(String leadingFourDigits) {
List matchedList = new ArrayList();
- List formatList = currentMetaData.getNumberFormatList();
+ List formatList =
+ (isInternationalFormatting && currentMetaData.getIntlNumberFormatCount() > 0)
+ ? currentMetaData.getIntlNumberFormatList()
+ : currentMetaData.getNumberFormatList();
for (NumberFormat format : formatList) {
if (format.hasLeadingDigits()) {
Pattern leadingDigitsPattern = Pattern.compile(format.getLeadingDigits());
@@ -164,6 +167,7 @@ public class AsYouTypeFormatter {
prefixBeforeNationalNumber = new StringBuffer();
nationalNumber = new StringBuffer();
ableToFormat = true;
+ isInternationalFormatting = false;
if (!currentMetaData.equals(defaultMetaData)) {
initializeCountrySpecificInfo(defaultCountry);
}
@@ -269,6 +273,7 @@ public class AsYouTypeFormatter {
nationalNumber = new StringBuffer();
Matcher iddMatcher = internationalPrefix.matcher(accruedInputWithoutFormatting);
if (iddMatcher.lookingAt()) {
+ isInternationalFormatting = true;
int startOfCountryCode = iddMatcher.end();
StringBuffer numberIncludeCountryCode =
new StringBuffer(accruedInputWithoutFormatting.substring(startOfCountryCode));
diff --git a/java/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java b/java/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java
index 96e820813..2b895f15c 100644
--- a/java/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java
+++ b/java/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java
@@ -18,6 +18,7 @@ package com.google.i18n.phonenumbers;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.i18n.phonenumbers.Phonemetadata.NumberFormat;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadataCollection;
@@ -49,9 +50,9 @@ import java.util.regex.Pattern;
* @author Lara Rennie
*/
public class PhoneNumberUtil {
- // The maximum and minimum length of the national significant number.
- private static final int MAX_LENGTH_FOR_NSN = 15;
+ // The minimum and maximum length of the national significant number.
private static final int MIN_LENGTH_FOR_NSN = 3;
+ private static final int MAX_LENGTH_FOR_NSN = 15;
private static final String META_DATA_FILE =
"/com/google/i18n/phonenumbers/src/generated_files/PhoneNumberMetadataProto";
private static final Logger LOGGER = Logger.getLogger(PhoneNumberUtil.class.getName());
@@ -154,6 +155,17 @@ public class PhoneNumberUtil {
.putAll(DIGIT_MAPPINGS)
.build();
+ // A list of all country codes where national significant numbers (excluding any national prefix)
+ // exist that start with a leading zero.
+ private static final Set LEADING_ZERO_COUNTRIES =
+ new ImmutableSet.Builder()
+ .add(39) // Italy
+ .add(225) // C™te d'Ivoire
+ .add(228) // Togo
+ .add(240) // Equatorial Guinea
+ .add(241) // Gabon
+ .build();
+
// Pattern that makes it easy to distinguish whether a country has a unique international dialing
// prefix or not. If a country has a unique international prefix (e.g. 011 in USA), it will be
// represented as a string that contains a sequence of ASCII digits. If there are multiple
@@ -161,15 +173,15 @@ public class PhoneNumberUtil {
// always contains character(s) other than ASCII digits.
// Note this regex also includes tilde, which signals waiting for the tone.
private static final Pattern UNIQUE_INTERNATIONAL_PREFIX =
- Pattern.compile("[\\d]+([~\u2053\u223C\uFF5E][\\d]+)?");
+ Pattern.compile("[\\d]+(?:[~\u2053\u223C\uFF5E][\\d]+)?");
// Regular expression of acceptable punctuation found in phone numbers. This excludes punctuation
// found as a leading character only.
// This consists of dash characters, white space characters, full stops, slashes,
// square brackets, parentheses and tildes. It also includes the letter 'x' as that is found as a
// placeholder for carrier information in some phone numbers.
- private static final String VALID_PUNCTUATION = "[-x\u2010-\u2015\u2212\uFF0D-\uFF0F " +
- "\u00A0\u200B\u2060\u3000()\uFF08\uFF09\uFF3B\uFF3D.\\[\\]/~\u2053\u223C\uFF5E]";
+ private static final String VALID_PUNCTUATION = "-x\u2010-\u2015\u2212\uFF0D-\uFF0F " +
+ "\u00A0\u200B\u2060\u3000()\uFF08\uFF09\uFF3B\uFF3D.\\[\\]/~\u2053\u223C\uFF5E";
// Digits accepted in phone numbers
private static final String VALID_DIGITS =
@@ -199,16 +211,25 @@ public class PhoneNumberUtil {
private static final String SECOND_NUMBER_START = "[\\\\/] *x";
private static final Pattern SECOND_NUMBER_START_PATTERN = Pattern.compile(SECOND_NUMBER_START);
+ // Regular expression of trailing characters that we want to remove. We remove all characters that
+ // are not alpha or numerical characters. The hash character is retained here, as it may signify
+ // the previous block was an extension.
+ private static final String UNWANTED_END_CHARS = "[[\\P{N}&&\\P{L}]&&[^#]]+$";
+ private static final Pattern UNWANTED_END_CHAR_PATTERN = Pattern.compile(UNWANTED_END_CHARS);
+
+ // We use this pattern to check if the phone number has at least three letters in it - if so, then
+ // we treat it as a number where some phone-number digits are represented by letters.
+ private static final Pattern VALID_ALPHA_PHONE_PATTERN = Pattern.compile("(?:.*?[A-Za-z]){3}.*");
+
// Regular expression of viable phone numbers. This is location independent. Checks we have at
// least three leading digits, and only valid punctuation, alpha characters and
- // digits in the phone number. Does not include extension data - this is read in from the
- // PhoneNumberMetaData.xml file at initialisation time.
+ // digits in the phone number. Does not include extension data.
// The symbol 'x' is allowed here as valid punctuation since it is often used as a placeholder for
// carrier codes, for example in Brazilian phone numbers.
// Corresponds to the following:
// plus_sign?([punctuation]*[digits]){3,}([punctuation]|[digits]|[alpha])*
private static final String VALID_PHONE_NUMBER =
- "[" + PLUS_CHARS + "]?(?:" + VALID_PUNCTUATION + "*[" + VALID_DIGITS + "]){3,}[" +
+ "[" + PLUS_CHARS + "]?(?:[" + VALID_PUNCTUATION + "]*[" + VALID_DIGITS + "]){3,}[" +
VALID_ALPHA + VALID_PUNCTUATION + VALID_DIGITS + "]*";
// Default extension prefix to use when formatting. This will be put in front of any extension
@@ -225,9 +246,9 @@ public class PhoneNumberUtil {
// the extension is written with a hash at the end, such as "- 503#".
// Note that the only capturing groups should be around the digits that you want to capture as
// part of the extension, or else parsing will fail!
- private static final String KNOWN_EXTN_PATTERNS = "[ \\u00A0\\t,]*(?:ext(?:ensio)?n?|" +
- "\\uFF45\\uFF58\\uFF54\\uFF4E?|[,x\\uFF58#\\uFF03~\\uFF5E]|int|\\uFF49\\uFF4E\\uFF54)" +
- "[:\\.\\uFF0E]?[ \\u00A0\\t,]*([" + VALID_DIGITS + "]{1,7})|[- ]+([" + VALID_DIGITS +
+ private static final String KNOWN_EXTN_PATTERNS = "[ \u00A0\\t,]*(?:ext(?:ensio)?n?|" +
+ "\uFF45\uFF58\uFF54\uFF4E?|[,x\uFF58#\uFF03~\uFF5E]|int|\uFF49\uFF4E\uFF54)" +
+ "[:\\.\uFF0E]?[ \u00A0\\t,]*([" + VALID_DIGITS + "]{1,7})|[- ]+([" + VALID_DIGITS +
"]{1,5})#";
// Regexp of all known extension prefixes used by different countries followed by 1 or more valid
@@ -239,7 +260,7 @@ public class PhoneNumberUtil {
// We append optionally the extension pattern to the end here, as a valid phone number may
// have an extension prefix appended, followed by 1 or more digits.
private static final Pattern VALID_PHONE_NUMBER_PATTERN =
- Pattern.compile(VALID_PHONE_NUMBER + "(?:" + EXTN_PATTERN + ")?",
+ Pattern.compile(VALID_PHONE_NUMBER + "(?:" + KNOWN_EXTN_PATTERNS + ")?",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
private static PhoneNumberUtil instance = null;
@@ -367,8 +388,12 @@ public class PhoneNumberUtil {
*/
@VisibleForTesting
static String extractPossibleNumber(String number) {
- // Remove leading and trailing whitespace.
- number = number.trim();
+ // Remove trailing non-alpha non-numerical characters.
+ Matcher trailingCharsMatcher = UNWANTED_END_CHAR_PATTERN.matcher(number);
+ if (trailingCharsMatcher.find()) {
+ number = number.substring(0, trailingCharsMatcher.start());
+ LOGGER.log(Level.FINER, "Stripped trailing characters: " + number);
+ }
Matcher m = VALID_START_CHAR_PATTERN.matcher(number);
if (m.find()) {
number = number.substring(m.start());
@@ -417,7 +442,8 @@ public class PhoneNumberUtil {
* @return the normalized string version of the phone number
*/
static String normalize(String number) {
- if (number.matches("(?:.*?[A-Za-z]){3}.*")) {
+ Matcher m = VALID_ALPHA_PHONE_PATTERN.matcher(number);
+ if (m.matches()) {
return normalizeHelper(number, ALL_NORMALIZATION_MAPPINGS, true);
} else {
return normalizeHelper(number, DIGIT_MAPPINGS, true);
@@ -438,7 +464,7 @@ public class PhoneNumberUtil {
/**
* Normalizes a string of characters representing a phone number. This converts wide-ascii and
- * arabic-indic numerals to European numerals, and strips punctuation and alpha characters,
+ * arabic-indic numerals to European numerals, and strips punctuation and alpha characters.
*
* @param number a string of characters representing a phone number
* @return the normalized string version of the phone number
@@ -503,15 +529,6 @@ public class PhoneNumberUtil {
instance = null;
}
- @VisibleForTesting
- PhoneMetadata getPhoneMetadata(String regionCode) {
- PhoneMetadata metadata = countryToMetadataMap.get(regionCode);
- // makes a defensive copy
- PhoneMetadata.Builder metadataCopy = metadata.newBuilder();
- metadataCopy.mergeFrom(metadata);
- return metadataCopy.build();
- }
-
/**
* Convenience method to enable tests to get a list of what countries the library has metadata
* for.
@@ -541,8 +558,8 @@ public class PhoneNumberUtil {
}
/**
- * Helper function to check region code is not unknown or null. The number supplied is used only
- * for the resultant log message.
+ * Helper function to check region code is not unknown or null. The countryCode and number
+ * supplied is used only for the resultant log message.
*/
private boolean isValidRegionCode(String regionCode, int countryCode, String number) {
if (regionCode == null || regionCode.equals("ZZ")) {
@@ -605,8 +622,9 @@ public class PhoneNumberUtil {
PhoneNumberFormat numberFormat,
List userDefinedFormats) {
int countryCode = number.getCountryCode();
- // For performance reasons, we use US to represent NANPA countries here. This means that
- // the extension symbol will be chosen from the US metadata.
+ // Note getRegionCodeForCountryCode() is used because formatting information for countries which
+ // share a country code is contained by only one country for performance reasons. For example,
+ // for NANPA countries it will be contained in the metadata for US.
String regionCode = getRegionCodeForCountryCode(countryCode);
String nationalSignificantNumber = getUnformattedNationalNumber(number);
if (!isValidRegionCode(regionCode, countryCode, nationalSignificantNumber)) {
@@ -662,7 +680,7 @@ public class PhoneNumberUtil {
return format(number, PhoneNumberFormat.INTERNATIONAL);
}
int countryCode = number.getCountryCode();
- if (countryCode == NANPA_COUNTRY_CODE && nanpaCountries.contains(countryCallingFrom)) {
+ if (countryCode == NANPA_COUNTRY_CODE && isNANPACountry(countryCallingFrom)) {
// For NANPA countries, return the national format for these countries but prefix it with the
// country code.
return countryCode + " " + format(number, PhoneNumberFormat.NATIONAL);
@@ -736,9 +754,9 @@ public class PhoneNumberUtil {
// number. There have been plans to migrate landline numbers to start with the digit two since
// December 2000, but it has not yet happened.
// See http://en.wikipedia.org/wiki/%2B39 for more details.
- // Cote d'Ivoire also uses this for some of their mobile numbers.
+ // Other countries such as Cote d'Ivoire and Gabon use this for their mobile numbers.
StringBuffer nationalNumber = new StringBuffer(
- ((number.getCountryCode() == 39 || number.getCountryCode() == 225) &&
+ (isLeadingZeroCountry(number.getCountryCode()) &&
number.hasItalianLeadingZero() &&
number.getItalianLeadingZero())
? "0" : ""
@@ -903,8 +921,7 @@ public class PhoneNumberUtil {
if (!isValidRegionCode(regionCode, number.getCountryCode(), nationalSignificantNumber)) {
return PhoneNumberType.UNKNOWN;
}
- PhoneMetadata metadata = getMetadataForRegion(regionCode);
- return getNumberTypeHelper(nationalSignificantNumber, metadata);
+ return getNumberTypeHelper(nationalSignificantNumber, getMetadataForRegion(regionCode));
}
private PhoneNumberType getNumberTypeHelper(String nationalNumber, PhoneMetadata metadata) {
@@ -972,13 +989,8 @@ public class PhoneNumberUtil {
}
private boolean isNumberMatchingDesc(String nationalNumber, PhoneNumberDesc numberDesc) {
- String possiblePattern = numberDesc.getPossibleNumberPattern();
- if (!nationalNumber.matches(possiblePattern)) {
- return false;
- }
-
- String validPattern = numberDesc.getNationalNumberPattern();
- return nationalNumber.matches(validPattern);
+ return nationalNumber.matches(numberDesc.getPossibleNumberPattern()) &&
+ nationalNumber.matches(numberDesc.getNationalNumberPattern());
}
/**
@@ -1016,7 +1028,7 @@ public class PhoneNumberUtil {
PhoneNumberDesc generalNumDesc = metadata.getGeneralDesc();
String nationalSignificantNumber = getUnformattedNationalNumber(number);
- // For countries where we don't have meta-data for PhoneNumberDesc, we treat any number passed
+ // For countries where we don't have metadata for PhoneNumberDesc, we treat any number passed
// in as a valid number if its national significant number is between the minimum and maximum
// lengths defined by ITU for a national significant number.
if (!generalNumDesc.hasNationalNumberPattern()) {
@@ -1037,7 +1049,6 @@ public class PhoneNumberUtil {
*/
public String getRegionCodeForNumber(PhoneNumber number) {
int countryCode = number.getCountryCode();
- String regionCode;
switch (countryCode) {
case NANPA_COUNTRY_CODE:
// Override this and try the US case first, since it is more likely than other countries,
@@ -1047,14 +1058,11 @@ public class PhoneNumberUtil {
}
Set nanpaExceptUS = new HashSet(nanpaCountries);
nanpaExceptUS.remove("US");
- regionCode = getRegionCodeForNumberFromRegionList(number, nanpaExceptUS);
- return regionCode;
+ return getRegionCodeForNumberFromRegionList(number, nanpaExceptUS);
case RUSSIAN_FED_COUNTRY_CODE:
- regionCode = getRegionCodeForNumberFromRegionList(number, russiaFederationCountries);
- return regionCode;
+ return getRegionCodeForNumberFromRegionList(number, russiaFederationCountries);
case FRENCH_INDIAN_OCEAN_COUNTRY_CODE:
- regionCode = getRegionCodeForNumberFromRegionList(number, frenchIndianOceanTerritories);
- return regionCode;
+ return getRegionCodeForNumberFromRegionList(number, frenchIndianOceanTerritories);
default:
return getRegionCodeForCountryCode(countryCode);
}
@@ -1064,8 +1072,8 @@ public class PhoneNumberUtil {
Set regionCodes) {
String nationalNumber = String.valueOf(number.getNationalNumber());
for (String regionCode : regionCodes) {
- PhoneMetadata metadata = getMetadataForRegion(regionCode);
- if (getNumberTypeHelper(nationalNumber, metadata) != PhoneNumberType.UNKNOWN) {
+ if (getNumberTypeHelper(nationalNumber, getMetadataForRegion(regionCode)) !=
+ PhoneNumberType.UNKNOWN) {
return regionCode;
}
}
@@ -1095,17 +1103,21 @@ public class PhoneNumberUtil {
return 0;
}
PhoneMetadata metadata = getMetadataForRegion(regionCode);
+ if (metadata == null) {
+ LOGGER.log(Level.SEVERE, "Unsupported country code provided.");
+ return 0;
+ }
return metadata.getCountryCode();
}
/**
- * Gets a set which contains all the countries under the North American Numbering Plan
+ * Check if a country is one of the countries under the North American Numbering Plan
* Administration (NANPA).
*
- * @return the set that contains the countries under NANPA
+ * @return true if regionCode is one of the countries under NANPA
*/
- public Set getNANPACountries() {
- return new HashSet(nanpaCountries);
+ public boolean isNANPACountry(String regionCode) {
+ return nanpaCountries.contains(regionCode);
}
/**
@@ -1118,6 +1130,14 @@ public class PhoneNumberUtil {
return isPossibleNumberWithReason(number) == 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.
+ */
+ public static boolean isLeadingZeroCountry(int countryCode) {
+ return LEADING_ZERO_COUNTRIES.contains(countryCode);
+ }
+
/**
* Check whether a phone number is a possible number. It provides a more lenient check than
* isValidNumber in the following sense:
@@ -1139,7 +1159,7 @@ public class PhoneNumberUtil {
* @return a ValidationResult object which indicates whether the number is possible
*/
public ValidationResult isPossibleNumberWithReason(PhoneNumber number) {
- String nationalNumber = String.valueOf(number.getNationalNumber());
+ String nationalNumber = getUnformattedNationalNumber(number);
int countryCode = number.getCountryCode();
// Note: For Russian Fed and NANPA numbers, we just use the rules from the default region (US or
// Russia) since the getRegionCodeForNumber will not work if the number is possible but not
@@ -1313,7 +1333,7 @@ public class PhoneNumberUtil {
// begin with 0.
Matcher digitMatcher = CAPTURING_DIGIT_PATTERN.matcher(number.substring(matchEnd));
if (digitMatcher.find()) {
- String normalizedGroup = normalize(digitMatcher.group(1));
+ String normalizedGroup = normalizeHelper(digitMatcher.group(1), DIGIT_MAPPINGS, true);
if (normalizedGroup.equals("0")) {
return false;
}
@@ -1456,7 +1476,31 @@ public class PhoneNumberUtil {
throw new NumberParseException(NumberParseException.ErrorType.INVALID_COUNTRY_CODE,
"No default country was supplied.");
}
- return parseHelper(numberToParse, defaultCountry);
+ return parseHelper(numberToParse, defaultCountry, false);
+ }
+
+ /**
+ * Parses a string and returns it in proto buffer format. This method differs from parse() in that
+ * it always populates the raw_input field of the protocol buffer with numberToParse.
+ *
+ * @param numberToParse number that we are attempting to parse. This can contain formatting
+ * such as +, ( and -, as well as a phone number extension.
+ * @param defaultCountry the ISO 3166-1 two-letter country code that 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.
+ * @return a phone number proto buffer filled with the parsed number
+ * @throws NumberParseException if the string is not considered to be a viable phone number or if
+ * no default country was supplied
+ */
+ public PhoneNumber parseAndKeepRawInput(String numberToParse, String defaultCountry)
+ throws NumberParseException {
+ if (defaultCountry == null || defaultCountry.equals("ZZ")) {
+ throw new NumberParseException(NumberParseException.ErrorType.INVALID_COUNTRY_CODE,
+ "No default country was supplied.");
+ }
+ return parseHelper(numberToParse, defaultCountry, true);
}
/**
@@ -1489,7 +1533,8 @@ public class PhoneNumberUtil {
* parse() method, with the exception that it allows the default country to be null, for use by
* isNumberMatch().
*/
- private PhoneNumber parseHelper(String numberToParse, String defaultCountry)
+ private PhoneNumber parseHelper(String numberToParse, String defaultCountry,
+ Boolean keepRawInput)
throws NumberParseException {
// Extract a possible number from the string passed in (this strips leading characters that
// could not be the start of a phone number.)
@@ -1500,6 +1545,9 @@ public class PhoneNumberUtil {
}
PhoneNumber.Builder phoneNumber = PhoneNumber.newBuilder();
+ if (keepRawInput) {
+ phoneNumber.setRawInput(numberToParse);
+ }
StringBuffer nationalNumber = new StringBuffer(number);
// Attempt to parse extension first, since it doesn't require country-specific data and we want
// to have the non-normalised number here.
@@ -1541,8 +1589,8 @@ public class PhoneNumberUtil {
validNumberPattern);
}
phoneNumber.setCountryCode(countryCode);
- // The ItalianLeadingZero is valid only for numbers from IT and CI.
- if ((countryCode == 39 || countryCode == 225) && normalizedNationalNumber.charAt(0) == '0') {
+ if (isLeadingZeroCountry(countryCode) &&
+ normalizedNationalNumber.charAt(0) == '0') {
phoneNumber.setItalianLeadingZero(true);
}
int lengthOfNationalNumber = normalizedNationalNumber.length();
@@ -1586,8 +1634,10 @@ public class PhoneNumberUtil {
firstNumber.mergeFrom(firstNumberIn);
PhoneNumber.Builder secondNumber = PhoneNumber.newBuilder();
secondNumber.mergeFrom(secondNumberIn);
- // First clear any empty-string extensions so that we can use the proto-buffer equality method.
-
+ // First clear raw_input field and any empty-string extensions so that we can use the
+ // proto-buffer equality method.
+ firstNumber.clearRawInput();
+ secondNumber.clearRawInput();
if (firstNumber.hasExtension() &&
firstNumber.getExtension().equals("")) {
firstNumber.clearExtension();
@@ -1611,17 +1661,12 @@ public class PhoneNumberUtil {
if (firstNumberCountryCode != 0 && secondNumberCountryCode != 0) {
if (areSameMessages(number1, number2)) {
return MatchType.EXACT_MATCH;
- } else if (firstNumberCountryCode == secondNumberCountryCode) {
+ } else if (firstNumberCountryCode == secondNumberCountryCode &&
+ isNationalNumberSuffixOfTheOther(number1, number2)) {
// A SHORT_NSN_MATCH occurs if there is a difference because of the presence or absence of
// an 'Italian leading zero', the presence or absence of an extension, or one NSN being a
// shorter variant of the other.
- String firstNumberNationalNumber = String.valueOf(number1.getNationalNumber());
- String secondNumberNationalNumber = String.valueOf(number2.getNationalNumber());
- // Note that endsWith returns true if the numbers are equal.
- if (firstNumberNationalNumber.endsWith(secondNumberNationalNumber) ||
- secondNumberNationalNumber.endsWith(firstNumberNationalNumber)) {
- return MatchType.SHORT_NSN_MATCH;
- }
+ return MatchType.SHORT_NSN_MATCH;
}
// This is not a match.
return MatchType.NO_MATCH;
@@ -1634,16 +1679,22 @@ public class PhoneNumberUtil {
if (areSameMessages(newNumber, number2)) {
return MatchType.NSN_MATCH;
}
- String firstNumberNationalNumber = String.valueOf(newNumber.getNationalNumber());
- String secondNumberNationalNumber = String.valueOf(number2.getNationalNumber());
- // Note that endsWith returns true if the numbers are equal.
- if (firstNumberNationalNumber.endsWith(secondNumberNationalNumber) ||
- secondNumberNationalNumber.endsWith(firstNumberNationalNumber)) {
+ if (isNationalNumberSuffixOfTheOther(newNumber, number2)) {
return MatchType.SHORT_NSN_MATCH;
}
return MatchType.NO_MATCH;
}
+ // Returns true when one national number is the suffix of the other or both are the same.
+ private boolean isNationalNumberSuffixOfTheOther(PhoneNumber firstNumber,
+ PhoneNumber secondNumber) {
+ String firstNumberNationalNumber = String.valueOf(firstNumber.getNationalNumber());
+ String secondNumberNationalNumber = String.valueOf(secondNumber.getNationalNumber());
+ // Note that endsWith returns true if the numbers are equal.
+ return firstNumberNationalNumber.endsWith(secondNumberNationalNumber) ||
+ secondNumberNationalNumber.endsWith(firstNumberNationalNumber);
+ }
+
/**
* Takes two phone numbers as strings and compares them for equality. This is a convenience
* wrapper for isNumberMatch(PhoneNumber firstNumber, PhoneNumber secondNumber). No default region
@@ -1660,7 +1711,8 @@ public class PhoneNumberUtil {
*/
public MatchType isNumberMatch(String firstNumber, String secondNumber)
throws NumberParseException {
- return isNumberMatch(parseHelper(firstNumber, null), parseHelper(secondNumber, null));
+ return isNumberMatch(parseHelper(firstNumber, null, false),
+ parseHelper(secondNumber, null, false));
}
/**
@@ -1677,6 +1729,6 @@ public class PhoneNumberUtil {
*/
public MatchType isNumberMatch(PhoneNumber firstNumber, String secondNumber)
throws NumberParseException {
- return isNumberMatch(firstNumber, parseHelper(secondNumber, null));
+ return isNumberMatch(firstNumber, parseHelper(secondNumber, null, false));
}
}
diff --git a/java/src/com/google/i18n/phonenumbers/Phonenumber.java b/java/src/com/google/i18n/phonenumbers/Phonenumber.java
index c3b508912..3a0b16724 100644
--- a/java/src/com/google/i18n/phonenumbers/Phonenumber.java
+++ b/java/src/com/google/i18n/phonenumbers/Phonenumber.java
@@ -53,6 +53,13 @@ public final class Phonenumber {
public boolean hasItalianLeadingZero() { return hasItalianLeadingZero; }
public boolean getItalianLeadingZero() { return italianLeadingZero_; }
+ // optional string raw_input = 5;
+ public static final int RAW_INPUT_FIELD_NUMBER = 5;
+ private boolean hasRawInput;
+ private java.lang.String rawInput_ = "";
+ public boolean hasRawInput() { return hasRawInput; }
+ public java.lang.String getRawInput() { return rawInput_; }
+
private void initFields() {
}
public final boolean isInitialized() {
@@ -76,6 +83,9 @@ public final class Phonenumber {
if (hasItalianLeadingZero()) {
output.writeBool(4, getItalianLeadingZero());
}
+ if (hasRawInput()) {
+ output.writeString(5, getRawInput());
+ }
}
private int memoizedSerializedSize = -1;
@@ -100,6 +110,10 @@ public final class Phonenumber {
size += com.google.protobuf.CodedOutputStream
.computeBoolSize(4, getItalianLeadingZero());
}
+ if (hasRawInput()) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeStringSize(5, getRawInput());
+ }
memoizedSerializedSize = size;
return size;
}
@@ -256,6 +270,9 @@ public final class Phonenumber {
if (other.hasItalianLeadingZero()) {
setItalianLeadingZero(other.getItalianLeadingZero());
}
+ if (other.hasRawInput()) {
+ setRawInput(other.getRawInput());
+ }
return this;
}
@@ -290,6 +307,10 @@ public final class Phonenumber {
setItalianLeadingZero(input.readBool());
break;
}
+ case 42: {
+ setRawInput(input.readString());
+ break;
+ }
}
}
}
@@ -370,6 +391,27 @@ public final class Phonenumber {
return this;
}
+ // optional string raw_input = 5;
+ public boolean hasRawInput() {
+ return result.hasRawInput();
+ }
+ public java.lang.String getRawInput() {
+ return result.getRawInput();
+ }
+ public Builder setRawInput(java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ result.hasRawInput = true;
+ result.rawInput_ = value;
+ return this;
+ }
+ public Builder clearRawInput() {
+ result.hasRawInput = false;
+ result.rawInput_ = getDefaultInstance().getRawInput();
+ return this;
+ }
+
// @@protoc_insertion_point(builder_scope:i18n.phonenumbers.PhoneNumber)
}
diff --git a/java/src/com/google/i18n/phonenumbers/phonenumber.proto b/java/src/com/google/i18n/phonenumbers/phonenumber.proto
index 42382746b..27b5996f8 100644
--- a/java/src/com/google/i18n/phonenumbers/phonenumber.proto
+++ b/java/src/com/google/i18n/phonenumbers/phonenumber.proto
@@ -50,6 +50,11 @@ message PhoneNumber {
// phone numbers. For an Italian phone number, if its national (significant) number starts
// with the digit zero, set this flag to true.
optional bool italian_leading_zero = 4;
+
+// This field is used to store the raw input string containing phone numbers before it was
+// canonicalized by the library. For example, it could be used to store alphanumerical numbers
+// such as "1-800-GOOG-411".
+ optional string raw_input = 5;
}
// Examples
diff --git a/java/test/com/google/i18n/phonenumbers/AsYouTypeFormatterTest.java b/java/test/com/google/i18n/phonenumbers/AsYouTypeFormatterTest.java
index 6eb77f949..4c114a57b 100644
--- a/java/test/com/google/i18n/phonenumbers/AsYouTypeFormatterTest.java
+++ b/java/test/com/google/i18n/phonenumbers/AsYouTypeFormatterTest.java
@@ -112,6 +112,25 @@ public class AsYouTypeFormatterTest extends TestCase {
assertEquals("011 44 6 123 123 12\u2008", formatter.inputDigit('2'));
assertEquals("011 44 6 123 123 123", formatter.inputDigit('3'));
+ formatter.clear();
+ assertEquals("0", formatter.inputDigit('0'));
+ assertEquals("01", formatter.inputDigit('1'));
+ assertEquals("011", formatter.inputDigit('1'));
+ assertEquals("0115", formatter.inputDigit('5'));
+ assertEquals("01154", formatter.inputDigit('4'));
+ assertEquals("011 54 9", formatter.inputDigit('9'));
+ assertEquals("011 54 91", formatter.inputDigit('1'));
+ assertEquals("011 54 911", formatter.inputDigit('1'));
+ assertEquals("011 54 9 11 2\u2008\u2008\u2008 \u2008\u2008\u2008\u2008",
+ formatter.inputDigit('2'));
+ assertEquals("011 54 9 11 23\u2008\u2008 \u2008\u2008\u2008\u2008", formatter.inputDigit('3'));
+ assertEquals("011 54 9 11 231\u2008 \u2008\u2008\u2008\u2008", formatter.inputDigit('1'));
+ assertEquals("011 54 9 11 2312 \u2008\u2008\u2008\u2008", formatter.inputDigit('2'));
+ assertEquals("011 54 9 11 2312 1\u2008\u2008\u2008", formatter.inputDigit('1'));
+ assertEquals("011 54 9 11 2312 12\u2008\u2008", formatter.inputDigit('2'));
+ assertEquals("011 54 9 11 2312 123\u2008", formatter.inputDigit('3'));
+ assertEquals("011 54 9 11 2312 1234", formatter.inputDigit('4'));
+
formatter.clear();
assertEquals("+", formatter.inputDigit('+'));
assertEquals("+1", formatter.inputDigit('1'));
@@ -229,4 +248,38 @@ public class AsYouTypeFormatterTest extends TestCase {
assertEquals("030123", formatter.inputDigit('3'));
assertEquals("0301234", formatter.inputDigit('4'));
}
+
+ public void testAsYouTypeFormatterAR() {
+ AsYouTypeFormatter formatter = phoneUtil.getAsYouTypeFormatter("AR");
+ assertEquals("0", formatter.inputDigit('0'));
+ assertEquals("01", formatter.inputDigit('1'));
+ assertEquals("011", formatter.inputDigit('1'));
+ assertEquals("0117", formatter.inputDigit('7'));
+ assertEquals("01170", formatter.inputDigit('0'));
+ assertEquals("011 703\u2008-\u2008\u2008\u2008\u2008", formatter.inputDigit('3'));
+ assertEquals("011 7031-\u2008\u2008\u2008\u2008", formatter.inputDigit('1'));
+ assertEquals("011 7031-3\u2008\u2008\u2008", formatter.inputDigit('3'));
+ assertEquals("011 7031-30\u2008\u2008", formatter.inputDigit('0'));
+ assertEquals("011 7031-300\u2008", formatter.inputDigit('0'));
+ assertEquals("011 7031-3000", formatter.inputDigit('0'));
+ }
+
+ public void testAsYouTypeFormatterARMobile() {
+ AsYouTypeFormatter formatter = phoneUtil.getAsYouTypeFormatter("AR");
+ assertEquals("+", formatter.inputDigit('+'));
+ assertEquals("+5", formatter.inputDigit('5'));
+ assertEquals("+54", formatter.inputDigit('4'));
+ assertEquals("+549", formatter.inputDigit('9'));
+ assertEquals("+5491", formatter.inputDigit('1'));
+ assertEquals("+54 911", formatter.inputDigit('1'));
+ assertEquals("+54 9 11 2\u2008\u2008\u2008 \u2008\u2008\u2008\u2008",
+ formatter.inputDigit('2'));
+ assertEquals("+54 9 11 23\u2008\u2008 \u2008\u2008\u2008\u2008", formatter.inputDigit('3'));
+ assertEquals("+54 9 11 231\u2008 \u2008\u2008\u2008\u2008", formatter.inputDigit('1'));
+ assertEquals("+54 9 11 2312 \u2008\u2008\u2008\u2008", formatter.inputDigit('2'));
+ assertEquals("+54 9 11 2312 1\u2008\u2008\u2008", formatter.inputDigit('1'));
+ assertEquals("+54 9 11 2312 12\u2008\u2008", formatter.inputDigit('2'));
+ assertEquals("+54 9 11 2312 123\u2008", formatter.inputDigit('3'));
+ assertEquals("+54 9 11 2312 1234", formatter.inputDigit('4'));
+ }
}
diff --git a/java/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java b/java/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java
index 0721fa619..746a3ed94 100644
--- a/java/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java
+++ b/java/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java
@@ -26,7 +26,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import java.util.regex.Pattern;
/**
@@ -65,7 +64,7 @@ public class PhoneNumberUtilTest extends TestCase {
}
public void testGetInstanceLoadUSMetadata() throws IOException {
- PhoneMetadata metadata = phoneUtil.getPhoneMetadata("US");
+ PhoneMetadata metadata = phoneUtil.getMetadataForRegion("US");
assertEquals("US", metadata.getId());
assertEquals(1, metadata.getCountryCode());
assertEquals("011", metadata.getInternationalPrefix());
@@ -86,7 +85,7 @@ public class PhoneNumberUtilTest extends TestCase {
}
public void testGetInstanceLoadDEMetadata() {
- PhoneMetadata metadata = phoneUtil.getPhoneMetadata("DE");
+ PhoneMetadata metadata = phoneUtil.getMetadataForRegion("DE");
assertEquals("DE", metadata.getId());
assertEquals(49, metadata.getCountryCode());
assertEquals("00", metadata.getInternationalPrefix());
@@ -105,7 +104,7 @@ public class PhoneNumberUtilTest extends TestCase {
}
public void testGetInstanceLoadARMetadata() {
- PhoneMetadata metadata = phoneUtil.getPhoneMetadata("AR");
+ PhoneMetadata metadata = phoneUtil.getMetadataForRegion("AR");
assertEquals("AR", metadata.getId());
assertEquals(54, metadata.getCountryCode());
assertEquals("00", metadata.getInternationalPrefix());
@@ -740,13 +739,15 @@ public class PhoneNumberUtilTest extends TestCase {
public void testGetCountryCodeForRegion() {
assertEquals(1, phoneUtil.getCountryCodeForRegion("US"));
assertEquals(64, phoneUtil.getCountryCodeForRegion("NZ"));
+ assertEquals(0, phoneUtil.getCountryCodeForRegion(null));
+ assertEquals(0, phoneUtil.getCountryCodeForRegion("ZZ"));
+ // CS is already deprecated so the library doesn't support it.
+ assertEquals(0, phoneUtil.getCountryCodeForRegion("CS"));
}
- public void testGetNANPACountries() {
- Set nanpaCountries = phoneUtil.getNANPACountries();
- assertEquals(2, nanpaCountries.size());
- assertTrue(nanpaCountries.contains("US"));
- assertTrue(nanpaCountries.contains("BS"));
+ public void testIsNANPACountry() {
+ assertTrue(phoneUtil.isNANPACountry("US"));
+ assertTrue(phoneUtil.isNANPACountry("BS"));
}
public void testIsPossibleNumber() {
@@ -857,6 +858,12 @@ public class PhoneNumberUtilTest extends TestCase {
assertEquals("", PhoneNumberUtil.extractPossibleNumber("Num-...."));
// Leading brackets are stripped - these are not used when parsing.
assertEquals("650) 253-0000", PhoneNumberUtil.extractPossibleNumber("(650) 253-0000"));
+
+ // Trailing non-alpha-numeric characters should be removed.
+ assertEquals("650) 253-0000", PhoneNumberUtil.extractPossibleNumber("(650) 253-0000..- .."));
+ assertEquals("650) 253-0000", PhoneNumberUtil.extractPossibleNumber("(650) 253-0000."));
+ // This case has a trailing RTL char.
+ assertEquals("650) 253-0000", PhoneNumberUtil.extractPossibleNumber("(650) 253-0000\u200F"));
}
public void testMaybeStripNationalPrefix() {
@@ -938,7 +945,7 @@ public class PhoneNumberUtilTest extends TestCase {
}
public void testMaybeExtractCountryCode() {
- PhoneMetadata metadata = phoneUtil.getPhoneMetadata("US");
+ PhoneMetadata metadata = phoneUtil.getMetadataForRegion("US");
// Note that for the US, the IDD is 011.
try {
String phoneNumber = "011112-3456789";
@@ -1312,6 +1319,14 @@ public class PhoneNumberUtilTest extends TestCase {
assertEquals(usWithExtension, phoneUtil.parse("(800) 901-3355 ext: 7246433", "US"));
}
+ public void testParseAndKeepRaw() throws Exception {
+ PhoneNumber alphaNumericNumber =
+ PhoneNumber.newBuilder().setCountryCode(1).setNationalNumber(180074935247L)
+ .setRawInput("1800 six-flags").build();
+ assertEquals(alphaNumericNumber,
+ phoneUtil.parseAndKeepRawInput("1800 six-flags", "US"));
+ }
+
public void testCountryWithNoNumberDesc() {
// Andorra is a country where we don't have PhoneNumberDesc info in the meta data.
PhoneNumber adNumber =