1 /* 2 * Copyright (C) 2009 The Libphonenumber Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.i18n.phonenumbers; 18 19 import com.google.i18n.phonenumbers.Phonemetadata.NumberFormat; 20 import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata; 21 import com.google.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc; 22 import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; 23 import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource; 24 import com.google.i18n.phonenumbers.internal.MatcherApi; 25 import com.google.i18n.phonenumbers.internal.RegexBasedMatcher; 26 import com.google.i18n.phonenumbers.internal.RegexCache; 27 28 import java.util.ArrayList; 29 import java.util.Arrays; 30 import java.util.Collections; 31 import java.util.EnumSet; 32 import java.util.HashMap; 33 import java.util.HashSet; 34 import java.util.Iterator; 35 import java.util.List; 36 import java.util.Map; 37 import java.util.Set; 38 import java.util.TreeSet; 39 import java.util.logging.Level; 40 import java.util.logging.Logger; 41 import java.util.regex.Matcher; 42 import java.util.regex.Pattern; 43 44 /** 45 * Utility for international phone numbers. Functionality includes formatting, parsing and 46 * validation. 47 * 48 * <p>If you use this library, and want to be notified about important changes, please sign up to 49 * our <a href="https://groups.google.com/forum/#!aboutgroup/libphonenumber-discuss">mailing list</a>. 50 * 51 * NOTE: A lot of methods in this class require Region Code strings. These must be provided using 52 * CLDR two-letter region-code format. These should be in upper-case. The list of the codes 53 * can be found here: 54 * http://www.unicode.org/cldr/charts/30/supplemental/territory_information.html 55 */ 56 public class PhoneNumberUtil { 57 private static final Logger logger = Logger.getLogger(PhoneNumberUtil.class.getName()); 58 59 /** Flags to use when compiling regular expressions for phone numbers. */ 60 static final int REGEX_FLAGS = Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE; 61 // The minimum and maximum length of the national significant number. 62 private static final int MIN_LENGTH_FOR_NSN = 2; 63 // The ITU says the maximum length should be 15, but we have found longer numbers in Germany. 64 static final int MAX_LENGTH_FOR_NSN = 17; 65 // The maximum length of the country calling code. 66 static final int MAX_LENGTH_COUNTRY_CODE = 3; 67 // We don't allow input strings for parsing to be longer than 250 chars. This prevents malicious 68 // input from overflowing the regular-expression engine. 69 private static final int MAX_INPUT_STRING_LENGTH = 250; 70 71 // Region-code for the unknown region. 72 private static final String UNKNOWN_REGION = "ZZ"; 73 74 private static final int NANPA_COUNTRY_CODE = 1; 75 76 // The prefix that needs to be inserted in front of a Colombian landline number when dialed from 77 // a mobile phone in Colombia. 78 private static final String COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX = "3"; 79 80 // Map of country calling codes that use a mobile token before the area code. One example of when 81 // this is relevant is when determining the length of the national destination code, which should 82 // be the length of the area code plus the length of the mobile token. 83 private static final Map<Integer, String> MOBILE_TOKEN_MAPPINGS; 84 85 // Set of country codes that have geographically assigned mobile numbers (see GEO_MOBILE_COUNTRIES 86 // below) which are not based on *area codes*. For example, in China mobile numbers start with a 87 // carrier indicator, and beyond that are geographically assigned: this carrier indicator is not 88 // considered to be an area code. 89 private static final Set<Integer> GEO_MOBILE_COUNTRIES_WITHOUT_MOBILE_AREA_CODES; 90 91 // Set of country calling codes that have geographically assigned mobile numbers. This may not be 92 // complete; we add calling codes case by case, as we find geographical mobile numbers or hear 93 // from user reports. Note that countries like the US, where we can't distinguish between 94 // fixed-line or mobile numbers, are not listed here, since we consider FIXED_LINE_OR_MOBILE to be 95 // a possibly geographically-related type anyway (like FIXED_LINE). 96 private static final Set<Integer> GEO_MOBILE_COUNTRIES; 97 98 // The PLUS_SIGN signifies the international prefix. 99 static final char PLUS_SIGN = '+'; 100 101 private static final char STAR_SIGN = '*'; 102 103 private static final String RFC3966_EXTN_PREFIX = ";ext="; 104 private static final String RFC3966_PREFIX = "tel:"; 105 private static final String RFC3966_PHONE_CONTEXT = ";phone-context="; 106 private static final String RFC3966_ISDN_SUBADDRESS = ";isub="; 107 108 // A map that contains characters that are essential when dialling. That means any of the 109 // characters in this map must not be removed from a number when dialling, otherwise the call 110 // will not reach the intended destination. 111 private static final Map<Character, Character> DIALLABLE_CHAR_MAPPINGS; 112 113 // Only upper-case variants of alpha characters are stored. 114 private static final Map<Character, Character> ALPHA_MAPPINGS; 115 116 // For performance reasons, amalgamate both into one map. 117 private static final Map<Character, Character> ALPHA_PHONE_MAPPINGS; 118 119 // Separate map of all symbols that we wish to retain when formatting alpha numbers. This 120 // includes digits, ASCII letters and number grouping symbols such as "-" and " ". 121 private static final Map<Character, Character> ALL_PLUS_NUMBER_GROUPING_SYMBOLS; 122 123 static { 124 HashMap<Integer, String> mobileTokenMap = new HashMap<Integer, String>(); 125 mobileTokenMap.put(54, "9"); 126 MOBILE_TOKEN_MAPPINGS = Collections.unmodifiableMap(mobileTokenMap); 127 128 HashSet<Integer> geoMobileCountriesWithoutMobileAreaCodes = new HashSet<Integer>(); 129 geoMobileCountriesWithoutMobileAreaCodes.add(86); // China 130 GEO_MOBILE_COUNTRIES_WITHOUT_MOBILE_AREA_CODES = 131 Collections.unmodifiableSet(geoMobileCountriesWithoutMobileAreaCodes); 132 133 HashSet<Integer> geoMobileCountries = new HashSet<Integer>(); 134 geoMobileCountries.add(52); // Mexico 135 geoMobileCountries.add(54); // Argentina 136 geoMobileCountries.add(55); // Brazil 137 geoMobileCountries.add(62); // Indonesia: some prefixes only (fixed CMDA wireless) 138 geoMobileCountries.addAll(geoMobileCountriesWithoutMobileAreaCodes); 139 GEO_MOBILE_COUNTRIES = Collections.unmodifiableSet(geoMobileCountries); 140 141 // Simple ASCII digits map used to populate ALPHA_PHONE_MAPPINGS and 142 // ALL_PLUS_NUMBER_GROUPING_SYMBOLS. 143 HashMap<Character, Character> asciiDigitMappings = new HashMap<Character, Character>(); 144 asciiDigitMappings.put('0', '0'); 145 asciiDigitMappings.put('1', '1'); 146 asciiDigitMappings.put('2', '2'); 147 asciiDigitMappings.put('3', '3'); 148 asciiDigitMappings.put('4', '4'); 149 asciiDigitMappings.put('5', '5'); 150 asciiDigitMappings.put('6', '6'); 151 asciiDigitMappings.put('7', '7'); 152 asciiDigitMappings.put('8', '8'); 153 asciiDigitMappings.put('9', '9'); 154 155 HashMap<Character, Character> alphaMap = new HashMap<Character, Character>(40); 156 alphaMap.put('A', '2'); 157 alphaMap.put('B', '2'); 158 alphaMap.put('C', '2'); 159 alphaMap.put('D', '3'); 160 alphaMap.put('E', '3'); 161 alphaMap.put('F', '3'); 162 alphaMap.put('G', '4'); 163 alphaMap.put('H', '4'); 164 alphaMap.put('I', '4'); 165 alphaMap.put('J', '5'); 166 alphaMap.put('K', '5'); 167 alphaMap.put('L', '5'); 168 alphaMap.put('M', '6'); 169 alphaMap.put('N', '6'); 170 alphaMap.put('O', '6'); 171 alphaMap.put('P', '7'); 172 alphaMap.put('Q', '7'); 173 alphaMap.put('R', '7'); 174 alphaMap.put('S', '7'); 175 alphaMap.put('T', '8'); 176 alphaMap.put('U', '8'); 177 alphaMap.put('V', '8'); 178 alphaMap.put('W', '9'); 179 alphaMap.put('X', '9'); 180 alphaMap.put('Y', '9'); 181 alphaMap.put('Z', '9'); 182 ALPHA_MAPPINGS = Collections.unmodifiableMap(alphaMap); 183 184 HashMap<Character, Character> combinedMap = new HashMap<Character, Character>(100); 185 combinedMap.putAll(ALPHA_MAPPINGS); 186 combinedMap.putAll(asciiDigitMappings); 187 ALPHA_PHONE_MAPPINGS = Collections.unmodifiableMap(combinedMap); 188 189 HashMap<Character, Character> diallableCharMap = new HashMap<Character, Character>(); 190 diallableCharMap.putAll(asciiDigitMappings); diallableCharMap.put(PLUS_SIGN, PLUS_SIGN)191 diallableCharMap.put(PLUS_SIGN, PLUS_SIGN); 192 diallableCharMap.put('*', '*'); 193 diallableCharMap.put('#', '#'); 194 DIALLABLE_CHAR_MAPPINGS = Collections.unmodifiableMap(diallableCharMap); 195 196 HashMap<Character, Character> allPlusNumberGroupings = new HashMap<Character, Character>(); 197 // Put (lower letter -> upper letter) and (upper letter -> upper letter) mappings. 198 for (char c : ALPHA_MAPPINGS.keySet()) { Character.toLowerCase(c)199 allPlusNumberGroupings.put(Character.toLowerCase(c), c); allPlusNumberGroupings.put(c, c)200 allPlusNumberGroupings.put(c, c); 201 } 202 allPlusNumberGroupings.putAll(asciiDigitMappings); 203 // Put grouping symbols. 204 allPlusNumberGroupings.put('-', '-'); 205 allPlusNumberGroupings.put('\uFF0D', '-'); 206 allPlusNumberGroupings.put('\u2010', '-'); 207 allPlusNumberGroupings.put('\u2011', '-'); 208 allPlusNumberGroupings.put('\u2012', '-'); 209 allPlusNumberGroupings.put('\u2013', '-'); 210 allPlusNumberGroupings.put('\u2014', '-'); 211 allPlusNumberGroupings.put('\u2015', '-'); 212 allPlusNumberGroupings.put('\u2212', '-'); 213 allPlusNumberGroupings.put('/', '/'); 214 allPlusNumberGroupings.put('\uFF0F', '/'); 215 allPlusNumberGroupings.put(' ', ' '); 216 allPlusNumberGroupings.put('\u3000', ' '); 217 allPlusNumberGroupings.put('\u2060', ' '); 218 allPlusNumberGroupings.put('.', '.'); 219 allPlusNumberGroupings.put('\uFF0E', '.'); 220 ALL_PLUS_NUMBER_GROUPING_SYMBOLS = Collections.unmodifiableMap(allPlusNumberGroupings); 221 } 222 223 // Pattern that makes it easy to distinguish whether a region has a single international dialing 224 // prefix or not. If a region has a single international prefix (e.g. 011 in USA), it will be 225 // represented as a string that contains a sequence of ASCII digits, and possibly a tilde, which 226 // signals waiting for the tone. If there are multiple available international prefixes in a 227 // region, they will be represented as a regex string that always contains one or more characters 228 // that are not ASCII digits or a tilde. 229 private static final Pattern SINGLE_INTERNATIONAL_PREFIX = 230 Pattern.compile("[\\d]+(?:[~\u2053\u223C\uFF5E][\\d]+)?"); 231 232 // Regular expression of acceptable punctuation found in phone numbers, used to find numbers in 233 // text and to decide what is a viable phone number. This excludes diallable characters. 234 // This consists of dash characters, white space characters, full stops, slashes, 235 // square brackets, parentheses and tildes. It also includes the letter 'x' as that is found as a 236 // placeholder for carrier information in some phone numbers. Full-width variants are also 237 // present. 238 static final String VALID_PUNCTUATION = "-x\u2010-\u2015\u2212\u30FC\uFF0D-\uFF0F " 239 + "\u00A0\u00AD\u200B\u2060\u3000()\uFF08\uFF09\uFF3B\uFF3D.\\[\\]/~\u2053\u223C\uFF5E"; 240 241 private static final String DIGITS = "\\p{Nd}"; 242 // We accept alpha characters in phone numbers, ASCII only, upper and lower case. 243 private static final String VALID_ALPHA = 244 Arrays.toString(ALPHA_MAPPINGS.keySet().toArray()).replaceAll("[, \\[\\]]", "") 245 + Arrays.toString(ALPHA_MAPPINGS.keySet().toArray()) 246 .toLowerCase().replaceAll("[, \\[\\]]", ""); 247 static final String PLUS_CHARS = "+\uFF0B"; 248 static final Pattern PLUS_CHARS_PATTERN = Pattern.compile("[" + PLUS_CHARS + "]+"); 249 private static final Pattern SEPARATOR_PATTERN = Pattern.compile("[" + VALID_PUNCTUATION + "]+"); 250 private static final Pattern CAPTURING_DIGIT_PATTERN = Pattern.compile("(" + DIGITS + ")"); 251 252 // Regular expression of acceptable characters that may start a phone number for the purposes of 253 // parsing. This allows us to strip away meaningless prefixes to phone numbers that may be 254 // mistakenly given to us. This consists of digits, the plus symbol and arabic-indic digits. This 255 // does not contain alpha characters, although they may be used later in the number. It also does 256 // not include other punctuation, as this will be stripped later during parsing and is of no 257 // information value when parsing a number. 258 private static final String VALID_START_CHAR = "[" + PLUS_CHARS + DIGITS + "]"; 259 private static final Pattern VALID_START_CHAR_PATTERN = Pattern.compile(VALID_START_CHAR); 260 261 // Regular expression of characters typically used to start a second phone number for the purposes 262 // of parsing. This allows us to strip off parts of the number that are actually the start of 263 // another number, such as for: (530) 583-6985 x302/x2303 -> the second extension here makes this 264 // actually two phone numbers, (530) 583-6985 x302 and (530) 583-6985 x2303. We remove the second 265 // extension so that the first number is parsed correctly. 266 private static final String SECOND_NUMBER_START = "[\\\\/] *x"; 267 static final Pattern SECOND_NUMBER_START_PATTERN = Pattern.compile(SECOND_NUMBER_START); 268 269 // Regular expression of trailing characters that we want to remove. We remove all characters that 270 // are not alpha or numerical characters. The hash character is retained here, as it may signify 271 // the previous block was an extension. 272 private static final String UNWANTED_END_CHARS = "[[\\P{N}&&\\P{L}]&&[^#]]+$"; 273 static final Pattern UNWANTED_END_CHAR_PATTERN = Pattern.compile(UNWANTED_END_CHARS); 274 275 // We use this pattern to check if the phone number has at least three letters in it - if so, then 276 // we treat it as a number where some phone-number digits are represented by letters. 277 private static final Pattern VALID_ALPHA_PHONE_PATTERN = Pattern.compile("(?:.*?[A-Za-z]){3}.*"); 278 279 // Regular expression of viable phone numbers. This is location independent. Checks we have at 280 // least three leading digits, and only valid punctuation, alpha characters and 281 // digits in the phone number. Does not include extension data. 282 // The symbol 'x' is allowed here as valid punctuation since it is often used as a placeholder for 283 // carrier codes, for example in Brazilian phone numbers. We also allow multiple "+" characters at 284 // the start. 285 // Corresponds to the following: 286 // [digits]{minLengthNsn}| 287 // plus_sign*(([punctuation]|[star])*[digits]){3,}([punctuation]|[star]|[digits]|[alpha])* 288 // 289 // The first reg-ex is to allow short numbers (two digits long) to be parsed if they are entered 290 // as "15" etc, but only if there is no punctuation in them. The second expression restricts the 291 // number of digits to three or more, but then allows them to be in international form, and to 292 // have alpha-characters and punctuation. 293 // 294 // Note VALID_PUNCTUATION starts with a -, so must be the first in the range. 295 private static final String VALID_PHONE_NUMBER = 296 DIGITS + "{" + MIN_LENGTH_FOR_NSN + "}" + "|" 297 + "[" + PLUS_CHARS + "]*+(?:[" + VALID_PUNCTUATION + STAR_SIGN + "]*" + DIGITS + "){3,}[" 298 + VALID_PUNCTUATION + STAR_SIGN + VALID_ALPHA + DIGITS + "]*"; 299 300 // Default extension prefix to use when formatting. This will be put in front of any extension 301 // component of the number, after the main national number is formatted. For example, if you wish 302 // the default extension formatting to be " extn: 3456", then you should specify " extn: " here 303 // as the default extension prefix. This can be overridden by region-specific preferences. 304 private static final String DEFAULT_EXTN_PREFIX = " ext. "; 305 306 // Regexp of all possible ways to write extensions, for use when parsing. This will be run as a 307 // case-insensitive regexp match. Wide character versions are also provided after each ASCII 308 // version. 309 private static final String EXTN_PATTERNS_FOR_PARSING = createExtnPattern(true); 310 static final String EXTN_PATTERNS_FOR_MATCHING = createExtnPattern(false); 311 312 /** 313 * Helper method for constructing regular expressions for parsing. Creates an expression that 314 * captures up to maxLength digits. 315 */ extnDigits(int maxLength)316 private static String extnDigits(int maxLength) { 317 return "(" + DIGITS + "{1," + maxLength + "})"; 318 } 319 320 /** 321 * Helper initialiser method to create the regular-expression pattern to match extensions. 322 * Note that there are currently six capturing groups for the extension itself. If this number is 323 * changed, MaybeStripExtension needs to be updated. 324 */ createExtnPattern(boolean forParsing)325 private static String createExtnPattern(boolean forParsing) { 326 // We cap the maximum length of an extension based on the ambiguity of the way the extension is 327 // prefixed. As per ITU, the officially allowed length for extensions is actually 40, but we 328 // don't support this since we haven't seen real examples and this introduces many false 329 // interpretations as the extension labels are not standardized. 330 int extLimitAfterExplicitLabel = 20; 331 int extLimitAfterLikelyLabel = 15; 332 int extLimitAfterAmbiguousChar = 9; 333 int extLimitWhenNotSure = 6; 334 335 String possibleSeparatorsBetweenNumberAndExtLabel = "[ \u00A0\\t,]*"; 336 // Optional full stop (.) or colon, followed by zero or more spaces/tabs/commas. 337 String possibleCharsAfterExtLabel = "[:\\.\uFF0E]?[ \u00A0\\t,-]*"; 338 String optionalExtnSuffix = "#?"; 339 340 // Here the extension is called out in more explicit way, i.e mentioning it obvious patterns 341 // like "ext.". Canonical-equivalence doesn't seem to be an option with Android java, so we 342 // allow two options for representing the accented o - the character itself, and one in the 343 // unicode decomposed form with the combining acute accent. 344 String explicitExtLabels = 345 "(?:e?xt(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45?\uFF58\uFF54\uFF4E?|\u0434\u043E\u0431|anexo)"; 346 // One-character symbols that can be used to indicate an extension, and less commonly used 347 // or more ambiguous extension labels. 348 String ambiguousExtLabels = "(?:[x\uFF58#\uFF03~\uFF5E]|int|\uFF49\uFF4E\uFF54)"; 349 // When extension is not separated clearly. 350 String ambiguousSeparator = "[- ]+"; 351 352 String rfcExtn = RFC3966_EXTN_PREFIX + extnDigits(extLimitAfterExplicitLabel); 353 String explicitExtn = possibleSeparatorsBetweenNumberAndExtLabel + explicitExtLabels 354 + possibleCharsAfterExtLabel + extnDigits(extLimitAfterExplicitLabel) 355 + optionalExtnSuffix; 356 String ambiguousExtn = possibleSeparatorsBetweenNumberAndExtLabel + ambiguousExtLabels 357 + possibleCharsAfterExtLabel + extnDigits(extLimitAfterAmbiguousChar) + optionalExtnSuffix; 358 String americanStyleExtnWithSuffix = ambiguousSeparator + extnDigits(extLimitWhenNotSure) + "#"; 359 360 // The first regular expression covers RFC 3966 format, where the extension is added using 361 // ";ext=". The second more generic where extension is mentioned with explicit labels like 362 // "ext:". In both the above cases we allow more numbers in extension than any other extension 363 // labels. The third one captures when single character extension labels or less commonly used 364 // labels are used. In such cases we capture fewer extension digits in order to reduce the 365 // chance of falsely interpreting two numbers beside each other as a number + extension. The 366 // fourth one covers the special case of American numbers where the extension is written with a 367 // hash at the end, such as "- 503#". 368 String extensionPattern = 369 rfcExtn + "|" 370 + explicitExtn + "|" 371 + ambiguousExtn + "|" 372 + americanStyleExtnWithSuffix; 373 // Additional pattern that is supported when parsing extensions, not when matching. 374 if (forParsing) { 375 // This is same as possibleSeparatorsBetweenNumberAndExtLabel, but not matching comma as 376 // extension label may have it. 377 String possibleSeparatorsNumberExtLabelNoComma = "[ \u00A0\\t]*"; 378 // ",," is commonly used for auto dialling the extension when connected. First comma is matched 379 // through possibleSeparatorsBetweenNumberAndExtLabel, so we do not repeat it here. Semi-colon 380 // works in Iphone and Android also to pop up a button with the extension number following. 381 String autoDiallingAndExtLabelsFound = "(?:,{2}|;)"; 382 383 String autoDiallingExtn = possibleSeparatorsNumberExtLabelNoComma 384 + autoDiallingAndExtLabelsFound + possibleCharsAfterExtLabel 385 + extnDigits(extLimitAfterLikelyLabel) + optionalExtnSuffix; 386 String onlyCommasExtn = possibleSeparatorsNumberExtLabelNoComma 387 + "(?:,)+" + possibleCharsAfterExtLabel + extnDigits(extLimitAfterAmbiguousChar) 388 + optionalExtnSuffix; 389 // Here the first pattern is exclusively for extension autodialling formats which are used 390 // when dialling and in this case we accept longer extensions. However, the second pattern 391 // is more liberal on the number of commas that acts as extension labels, so we have a strict 392 // cap on the number of digits in such extensions. 393 return extensionPattern + "|" 394 + autoDiallingExtn + "|" 395 + onlyCommasExtn; 396 } 397 return extensionPattern; 398 } 399 400 // Regexp of all known extension prefixes used by different regions followed by 1 or more valid 401 // digits, for use when parsing. 402 private static final Pattern EXTN_PATTERN = 403 Pattern.compile("(?:" + EXTN_PATTERNS_FOR_PARSING + ")$", REGEX_FLAGS); 404 405 // We append optionally the extension pattern to the end here, as a valid phone number may 406 // have an extension prefix appended, followed by 1 or more digits. 407 private static final Pattern VALID_PHONE_NUMBER_PATTERN = 408 Pattern.compile(VALID_PHONE_NUMBER + "(?:" + EXTN_PATTERNS_FOR_PARSING + ")?", REGEX_FLAGS); 409 410 static final Pattern NON_DIGITS_PATTERN = Pattern.compile("(\\D+)"); 411 412 // The FIRST_GROUP_PATTERN was originally set to $1 but there are some countries for which the 413 // first group is not used in the national pattern (e.g. Argentina) so the $1 group does not match 414 // correctly. Therefore, we use \d, so that the first group actually used in the pattern will be 415 // matched. 416 private static final Pattern FIRST_GROUP_PATTERN = Pattern.compile("(\\$\\d)"); 417 // Constants used in the formatting rules to represent the national prefix, first group and 418 // carrier code respectively. 419 private static final String NP_STRING = "$NP"; 420 private static final String FG_STRING = "$FG"; 421 private static final String CC_STRING = "$CC"; 422 423 // A pattern that is used to determine if the national prefix formatting rule has the first group 424 // only, i.e., does not start with the national prefix. Note that the pattern explicitly allows 425 // for unbalanced parentheses. 426 private static final Pattern FIRST_GROUP_ONLY_PREFIX_PATTERN = Pattern.compile("\\(?\\$1\\)?"); 427 428 private static PhoneNumberUtil instance = null; 429 430 public static final String REGION_CODE_FOR_NON_GEO_ENTITY = "001"; 431 432 /** 433 * INTERNATIONAL and NATIONAL formats are consistent with the definition in ITU-T Recommendation 434 * E.123. However we follow local conventions such as using '-' instead of whitespace as 435 * separators. For example, the number of the Google Switzerland office will be written as 436 * "+41 44 668 1800" in INTERNATIONAL format, and as "044 668 1800" in NATIONAL format. E164 437 * format is as per INTERNATIONAL format but with no formatting applied, e.g. "+41446681800". 438 * RFC3966 is as per INTERNATIONAL format, but with all spaces and other separating symbols 439 * replaced with a hyphen, and with any phone number extension appended with ";ext=". It also 440 * will have a prefix of "tel:" added, e.g. "tel:+41-44-668-1800". 441 * 442 * Note: If you are considering storing the number in a neutral format, you are highly advised to 443 * use the PhoneNumber class. 444 */ 445 public enum PhoneNumberFormat { 446 E164, 447 INTERNATIONAL, 448 NATIONAL, 449 RFC3966 450 } 451 452 /** 453 * Type of phone numbers. 454 */ 455 public enum PhoneNumberType { 456 FIXED_LINE, 457 MOBILE, 458 // In some regions (e.g. the USA), it is impossible to distinguish between fixed-line and 459 // mobile numbers by looking at the phone number itself. 460 FIXED_LINE_OR_MOBILE, 461 // Freephone lines 462 TOLL_FREE, 463 PREMIUM_RATE, 464 // The cost of this call is shared between the caller and the recipient, and is hence typically 465 // less than PREMIUM_RATE calls. See // http://en.wikipedia.org/wiki/Shared_Cost_Service for 466 // more information. 467 SHARED_COST, 468 // Voice over IP numbers. This includes TSoIP (Telephony Service over IP). 469 VOIP, 470 // A personal number is associated with a particular person, and may be routed to either a 471 // MOBILE or FIXED_LINE number. Some more information can be found here: 472 // http://en.wikipedia.org/wiki/Personal_Numbers 473 PERSONAL_NUMBER, 474 PAGER, 475 // Used for "Universal Access Numbers" or "Company Numbers". They may be further routed to 476 // specific offices, but allow one number to be used for a company. 477 UAN, 478 // Used for "Voice Mail Access Numbers". 479 VOICEMAIL, 480 // A phone number is of type UNKNOWN when it does not fit any of the known patterns for a 481 // specific region. 482 UNKNOWN 483 } 484 485 /** 486 * Types of phone number matches. See detailed description beside the isNumberMatch() method. 487 */ 488 public enum MatchType { 489 NOT_A_NUMBER, 490 NO_MATCH, 491 SHORT_NSN_MATCH, 492 NSN_MATCH, 493 EXACT_MATCH, 494 } 495 496 /** 497 * Possible outcomes when testing if a PhoneNumber is possible. 498 */ 499 public enum ValidationResult { 500 /** The number length matches that of valid numbers for this region. */ 501 IS_POSSIBLE, 502 /** 503 * The number length matches that of local numbers for this region only (i.e. numbers that may 504 * be able to be dialled within an area, but do not have all the information to be dialled from 505 * anywhere inside or outside the country). 506 */ 507 IS_POSSIBLE_LOCAL_ONLY, 508 /** The number has an invalid country calling code. */ 509 INVALID_COUNTRY_CODE, 510 /** The number is shorter than all valid numbers for this region. */ 511 TOO_SHORT, 512 /** 513 * The number is longer than the shortest valid numbers for this region, shorter than the 514 * longest valid numbers for this region, and does not itself have a number length that matches 515 * valid numbers for this region. This can also be returned in the case where 516 * isPossibleNumberForTypeWithReason was called, and there are no numbers of this type at all 517 * for this region. 518 */ 519 INVALID_LENGTH, 520 /** The number is longer than all valid numbers for this region. */ 521 TOO_LONG, 522 } 523 524 /** 525 * Leniency when {@linkplain PhoneNumberUtil#findNumbers finding} potential phone numbers in text 526 * segments. The levels here are ordered in increasing strictness. 527 */ 528 public enum Leniency { 529 /** 530 * Phone numbers accepted are {@linkplain PhoneNumberUtil#isPossibleNumber(PhoneNumber) 531 * possible}, but not necessarily {@linkplain PhoneNumberUtil#isValidNumber(PhoneNumber) valid}. 532 */ 533 POSSIBLE { 534 @Override verify( PhoneNumber number, CharSequence candidate, PhoneNumberUtil util, PhoneNumberMatcher matcher)535 boolean verify( 536 PhoneNumber number, 537 CharSequence candidate, 538 PhoneNumberUtil util, 539 PhoneNumberMatcher matcher) { 540 return util.isPossibleNumber(number); 541 } 542 }, 543 /** 544 * Phone numbers accepted are {@linkplain PhoneNumberUtil#isPossibleNumber(PhoneNumber) 545 * possible} and {@linkplain PhoneNumberUtil#isValidNumber(PhoneNumber) valid}. Numbers written 546 * in national format must have their national-prefix present if it is usually written for a 547 * number of this type. 548 */ 549 VALID { 550 @Override verify( PhoneNumber number, CharSequence candidate, PhoneNumberUtil util, PhoneNumberMatcher matcher)551 boolean verify( 552 PhoneNumber number, 553 CharSequence candidate, 554 PhoneNumberUtil util, 555 PhoneNumberMatcher matcher) { 556 if (!util.isValidNumber(number) 557 || !PhoneNumberMatcher.containsOnlyValidXChars(number, candidate.toString(), util)) { 558 return false; 559 } 560 return PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util); 561 } 562 }, 563 /** 564 * Phone numbers accepted are {@linkplain PhoneNumberUtil#isValidNumber(PhoneNumber) valid} and 565 * are grouped in a possible way for this locale. For example, a US number written as 566 * "65 02 53 00 00" and "650253 0000" are not accepted at this leniency level, whereas 567 * "650 253 0000", "650 2530000" or "6502530000" are. 568 * Numbers with more than one '/' symbol in the national significant number are also dropped at 569 * this level. 570 * <p> 571 * Warning: This level might result in lower coverage especially for regions outside of country 572 * code "+1". If you are not sure about which level to use, email the discussion group 573 * libphonenumber-discuss@googlegroups.com. 574 */ 575 STRICT_GROUPING { 576 @Override verify( PhoneNumber number, CharSequence candidate, PhoneNumberUtil util, PhoneNumberMatcher matcher)577 boolean verify( 578 PhoneNumber number, 579 CharSequence candidate, 580 PhoneNumberUtil util, 581 PhoneNumberMatcher matcher) { 582 String candidateString = candidate.toString(); 583 if (!util.isValidNumber(number) 584 || !PhoneNumberMatcher.containsOnlyValidXChars(number, candidateString, util) 585 || PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidateString) 586 || !PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util)) { 587 return false; 588 } 589 return matcher.checkNumberGroupingIsValid( 590 number, candidate, util, new PhoneNumberMatcher.NumberGroupingChecker() { 591 @Override 592 public boolean checkGroups(PhoneNumberUtil util, PhoneNumber number, 593 StringBuilder normalizedCandidate, 594 String[] expectedNumberGroups) { 595 return PhoneNumberMatcher.allNumberGroupsRemainGrouped( 596 util, number, normalizedCandidate, expectedNumberGroups); 597 } 598 }); 599 } 600 }, 601 /** 602 * Phone numbers accepted are {@linkplain PhoneNumberUtil#isValidNumber(PhoneNumber) valid} and 603 * are grouped in the same way that we would have formatted it, or as a single block. For 604 * example, a US number written as "650 2530000" is not accepted at this leniency level, whereas 605 * "650 253 0000" or "6502530000" are. 606 * Numbers with more than one '/' symbol are also dropped at this level. 607 * <p> 608 * Warning: This level might result in lower coverage especially for regions outside of country 609 * code "+1". If you are not sure about which level to use, email the discussion group 610 * libphonenumber-discuss@googlegroups.com. 611 */ 612 EXACT_GROUPING { 613 @Override verify( PhoneNumber number, CharSequence candidate, PhoneNumberUtil util, PhoneNumberMatcher matcher)614 boolean verify( 615 PhoneNumber number, 616 CharSequence candidate, 617 PhoneNumberUtil util, 618 PhoneNumberMatcher matcher) { 619 String candidateString = candidate.toString(); 620 if (!util.isValidNumber(number) 621 || !PhoneNumberMatcher.containsOnlyValidXChars(number, candidateString, util) 622 || PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidateString) 623 || !PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util)) { 624 return false; 625 } 626 return matcher.checkNumberGroupingIsValid( 627 number, candidate, util, new PhoneNumberMatcher.NumberGroupingChecker() { 628 @Override 629 public boolean checkGroups(PhoneNumberUtil util, PhoneNumber number, 630 StringBuilder normalizedCandidate, 631 String[] expectedNumberGroups) { 632 return PhoneNumberMatcher.allNumberGroupsAreExactlyPresent( 633 util, number, normalizedCandidate, expectedNumberGroups); 634 } 635 }); 636 } 637 }; 638 639 /** Returns true if {@code number} is a verified number according to this leniency. */ 640 abstract boolean verify( 641 PhoneNumber number, 642 CharSequence candidate, 643 PhoneNumberUtil util, 644 PhoneNumberMatcher matcher); 645 } 646 647 // A source of metadata for different regions. 648 private final MetadataSource metadataSource; 649 650 // A mapping from a country calling code to the region codes which denote the region represented 651 // by that country calling code. In the case of multiple regions sharing a calling code, such as 652 // the NANPA regions, the one indicated with "isMainCountryForCode" in the metadata should be 653 // first. 654 private final Map<Integer, List<String>> countryCallingCodeToRegionCodeMap; 655 656 // An API for validation checking. 657 private final MatcherApi matcherApi = RegexBasedMatcher.create(); 658 659 // The set of regions that share country calling code 1. 660 // There are roughly 26 regions. 661 // We set the initial capacity of the HashSet to 35 to offer a load factor of roughly 0.75. 662 private final Set<String> nanpaRegions = new HashSet<String>(35); 663 664 // A cache for frequently used region-specific regular expressions. 665 // The initial capacity is set to 100 as this seems to be an optimal value for Android, based on 666 // performance measurements. 667 private final RegexCache regexCache = new RegexCache(100); 668 669 // The set of regions the library supports. 670 // There are roughly 240 of them and we set the initial capacity of the HashSet to 320 to offer a 671 // load factor of roughly 0.75. 672 private final Set<String> supportedRegions = new HashSet<String>(320); 673 674 // The set of country calling codes that map to the non-geo entity region ("001"). This set 675 // currently contains < 12 elements so the default capacity of 16 (load factor=0.75) is fine. 676 private final Set<Integer> countryCodesForNonGeographicalRegion = new HashSet<Integer>(); 677 678 /** 679 * This class implements a singleton, the constructor is only visible to facilitate testing. 680 */ 681 // @VisibleForTesting 682 PhoneNumberUtil(MetadataSource metadataSource, 683 Map<Integer, List<String>> countryCallingCodeToRegionCodeMap) { 684 this.metadataSource = metadataSource; 685 this.countryCallingCodeToRegionCodeMap = countryCallingCodeToRegionCodeMap; 686 for (Map.Entry<Integer, List<String>> entry : countryCallingCodeToRegionCodeMap.entrySet()) { 687 List<String> regionCodes = entry.getValue(); 688 // We can assume that if the country calling code maps to the non-geo entity region code then 689 // that's the only region code it maps to. 690 if (regionCodes.size() == 1 && REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCodes.get(0))) { 691 // This is the subset of all country codes that map to the non-geo entity region code. 692 countryCodesForNonGeographicalRegion.add(entry.getKey()); 693 } else { 694 // The supported regions set does not include the "001" non-geo entity region code. 695 supportedRegions.addAll(regionCodes); 696 } 697 } 698 // If the non-geo entity still got added to the set of supported regions it must be because 699 // there are entries that list the non-geo entity alongside normal regions (which is wrong). 700 // If we discover this, remove the non-geo entity from the set of supported regions and log. 701 if (supportedRegions.remove(REGION_CODE_FOR_NON_GEO_ENTITY)) { 702 logger.log(Level.WARNING, "invalid metadata (country calling code was mapped to the non-geo " 703 + "entity as well as specific region(s))"); 704 } 705 nanpaRegions.addAll(countryCallingCodeToRegionCodeMap.get(NANPA_COUNTRY_CODE)); 706 } 707 708 /** 709 * Attempts to extract a possible number from the string passed in. This currently strips all 710 * leading characters that cannot be used to start a phone number. Characters that can be used to 711 * start a phone number are defined in the VALID_START_CHAR_PATTERN. If none of these characters 712 * are found in the number passed in, an empty string is returned. This function also attempts to 713 * strip off any alternative extensions or endings if two or more are present, such as in the case 714 * of: (530) 583-6985 x302/x2303. The second extension here makes this actually two phone numbers, 715 * (530) 583-6985 x302 and (530) 583-6985 x2303. We remove the second extension so that the first 716 * number is parsed correctly. 717 * 718 * @param number the string that might contain a phone number 719 * @return the number, stripped of any non-phone-number prefix (such as "Tel:") or an empty 720 * string if no character used to start phone numbers (such as + or any digit) is found in the 721 * number 722 */ 723 static CharSequence extractPossibleNumber(CharSequence number) { 724 Matcher m = VALID_START_CHAR_PATTERN.matcher(number); 725 if (m.find()) { 726 number = number.subSequence(m.start(), number.length()); 727 // Remove trailing non-alpha non-numerical characters. 728 Matcher trailingCharsMatcher = UNWANTED_END_CHAR_PATTERN.matcher(number); 729 if (trailingCharsMatcher.find()) { 730 number = number.subSequence(0, trailingCharsMatcher.start()); 731 } 732 // Check for extra numbers at the end. 733 Matcher secondNumber = SECOND_NUMBER_START_PATTERN.matcher(number); 734 if (secondNumber.find()) { 735 number = number.subSequence(0, secondNumber.start()); 736 } 737 return number; 738 } else { 739 return ""; 740 } 741 } 742 743 /** 744 * Checks to see if the string of characters could possibly be a phone number at all. At the 745 * moment, checks to see that the string begins with at least 2 digits, ignoring any punctuation 746 * commonly found in phone numbers. 747 * This method does not require the number to be normalized in advance - but does assume that 748 * leading non-number symbols have been removed, such as by the method extractPossibleNumber. 749 * 750 * @param number string to be checked for viability as a phone number 751 * @return true if the number could be a phone number of some sort, otherwise false 752 */ 753 // @VisibleForTesting 754 static boolean isViablePhoneNumber(CharSequence number) { 755 if (number.length() < MIN_LENGTH_FOR_NSN) { 756 return false; 757 } 758 Matcher m = VALID_PHONE_NUMBER_PATTERN.matcher(number); 759 return m.matches(); 760 } 761 762 /** 763 * Normalizes a string of characters representing a phone number. This performs the following 764 * conversions: 765 * - Punctuation is stripped. 766 * For ALPHA/VANITY numbers: 767 * - Letters are converted to their numeric representation on a telephone keypad. The keypad 768 * used here is the one defined in ITU Recommendation E.161. This is only done if there are 3 769 * or more letters in the number, to lessen the risk that such letters are typos. 770 * For other numbers: 771 * - Wide-ascii digits are converted to normal ASCII (European) digits. 772 * - Arabic-Indic numerals are converted to European numerals. 773 * - Spurious alpha characters are stripped. 774 * 775 * @param number a StringBuilder of characters representing a phone number that will be 776 * normalized in place 777 */ 778 static StringBuilder normalize(StringBuilder number) { 779 Matcher m = VALID_ALPHA_PHONE_PATTERN.matcher(number); 780 if (m.matches()) { 781 number.replace(0, number.length(), normalizeHelper(number, ALPHA_PHONE_MAPPINGS, true)); 782 } else { 783 number.replace(0, number.length(), normalizeDigitsOnly(number)); 784 } 785 return number; 786 } 787 788 /** 789 * Normalizes a string of characters representing a phone number. This converts wide-ascii and 790 * arabic-indic numerals to European numerals, and strips punctuation and alpha characters. 791 * 792 * @param number a string of characters representing a phone number 793 * @return the normalized string version of the phone number 794 */ 795 public static String normalizeDigitsOnly(CharSequence number) { 796 return normalizeDigits(number, false /* strip non-digits */).toString(); 797 } 798 799 static StringBuilder normalizeDigits(CharSequence number, boolean keepNonDigits) { 800 StringBuilder normalizedDigits = new StringBuilder(number.length()); 801 for (int i = 0; i < number.length(); i++) { 802 char c = number.charAt(i); 803 int digit = Character.digit(c, 10); 804 if (digit != -1) { 805 normalizedDigits.append(digit); 806 } else if (keepNonDigits) { 807 normalizedDigits.append(c); 808 } 809 } 810 return normalizedDigits; 811 } 812 813 /** 814 * Normalizes a string of characters representing a phone number. This strips all characters which 815 * are not diallable on a mobile phone keypad (including all non-ASCII digits). 816 * 817 * @param number a string of characters representing a phone number 818 * @return the normalized string version of the phone number 819 */ 820 public static String normalizeDiallableCharsOnly(CharSequence number) { 821 return normalizeHelper(number, DIALLABLE_CHAR_MAPPINGS, true /* remove non matches */); 822 } 823 824 /** 825 * Converts all alpha characters in a number to their respective digits on a keypad, but retains 826 * existing formatting. 827 */ 828 public static String convertAlphaCharactersInNumber(CharSequence number) { 829 return normalizeHelper(number, ALPHA_PHONE_MAPPINGS, false); 830 } 831 832 /** 833 * Gets the length of the geographical area code from the 834 * PhoneNumber object passed in, so that clients could use it 835 * to split a national significant number into geographical area code and subscriber number. It 836 * works in such a way that the resultant subscriber number should be diallable, at least on some 837 * devices. An example of how this could be used: 838 * 839 * <pre>{@code 840 * PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); 841 * PhoneNumber number = phoneUtil.parse("16502530000", "US"); 842 * String nationalSignificantNumber = phoneUtil.getNationalSignificantNumber(number); 843 * String areaCode; 844 * String subscriberNumber; 845 * 846 * int areaCodeLength = phoneUtil.getLengthOfGeographicalAreaCode(number); 847 * if (areaCodeLength > 0) { 848 * areaCode = nationalSignificantNumber.substring(0, areaCodeLength); 849 * subscriberNumber = nationalSignificantNumber.substring(areaCodeLength); 850 * } else { 851 * areaCode = ""; 852 * subscriberNumber = nationalSignificantNumber; 853 * } 854 * }</pre> 855 * 856 * N.B.: area code is a very ambiguous concept, so the I18N team generally recommends against 857 * using it for most purposes, but recommends using the more general {@code national_number} 858 * instead. Read the following carefully before deciding to use this method: 859 * <ul> 860 * <li> geographical area codes change over time, and this method honors those changes; 861 * therefore, it doesn't guarantee the stability of the result it produces. 862 * <li> subscriber numbers may not be diallable from all devices (notably mobile devices, which 863 * typically requires the full national_number to be dialled in most regions). 864 * <li> most non-geographical numbers have no area codes, including numbers from non-geographical 865 * entities 866 * <li> some geographical numbers have no area codes. 867 * </ul> 868 * @param number the PhoneNumber object for which clients 869 * want to know the length of the area code 870 * @return the length of area code of the PhoneNumber object 871 * passed in 872 */ 873 public int getLengthOfGeographicalAreaCode(PhoneNumber number) { 874 PhoneMetadata metadata = getMetadataForRegion(getRegionCodeForNumber(number)); 875 if (metadata == null) { 876 return 0; 877 } 878 // If a country doesn't use a national prefix, and this number doesn't have an Italian leading 879 // zero, we assume it is a closed dialling plan with no area codes. 880 if (!metadata.hasNationalPrefix() && !number.isItalianLeadingZero()) { 881 return 0; 882 } 883 884 PhoneNumberType type = getNumberType(number); 885 int countryCallingCode = number.getCountryCode(); 886 if (type == PhoneNumberType.MOBILE 887 // Note this is a rough heuristic; it doesn't cover Indonesia well, for example, where area 888 // codes are present for some mobile phones but not for others. We have no better way of 889 // representing this in the metadata at this point. 890 && GEO_MOBILE_COUNTRIES_WITHOUT_MOBILE_AREA_CODES.contains(countryCallingCode)) { 891 return 0; 892 } 893 894 if (!isNumberGeographical(type, countryCallingCode)) { 895 return 0; 896 } 897 898 return getLengthOfNationalDestinationCode(number); 899 } 900 901 /** 902 * Gets the length of the national destination code (NDC) from the 903 * PhoneNumber object passed in, so that clients could use it 904 * to split a national significant number into NDC and subscriber number. The NDC of a phone 905 * number is normally the first group of digit(s) right after the country calling code when the 906 * number is formatted in the international format, if there is a subscriber number part that 907 * follows. 908 * 909 * N.B.: similar to an area code, not all numbers have an NDC! 910 * 911 * An example of how this could be used: 912 * 913 * <pre>{@code 914 * PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); 915 * PhoneNumber number = phoneUtil.parse("18002530000", "US"); 916 * String nationalSignificantNumber = phoneUtil.getNationalSignificantNumber(number); 917 * String nationalDestinationCode; 918 * String subscriberNumber; 919 * 920 * int nationalDestinationCodeLength = phoneUtil.getLengthOfNationalDestinationCode(number); 921 * if (nationalDestinationCodeLength > 0) { 922 * nationalDestinationCode = nationalSignificantNumber.substring(0, 923 * nationalDestinationCodeLength); 924 * subscriberNumber = nationalSignificantNumber.substring(nationalDestinationCodeLength); 925 * } else { 926 * nationalDestinationCode = ""; 927 * subscriberNumber = nationalSignificantNumber; 928 * } 929 * }</pre> 930 * 931 * Refer to the unittests to see the difference between this function and 932 * {@link #getLengthOfGeographicalAreaCode}. 933 * 934 * @param number the PhoneNumber object for which clients 935 * want to know the length of the NDC 936 * @return the length of NDC of the PhoneNumber object 937 * passed in, which could be zero 938 */ 939 public int getLengthOfNationalDestinationCode(PhoneNumber number) { 940 PhoneNumber copiedProto; 941 if (number.hasExtension()) { 942 // We don't want to alter the proto given to us, but we don't want to include the extension 943 // when we format it, so we copy it and clear the extension here. 944 copiedProto = new PhoneNumber(); 945 copiedProto.mergeFrom(number); 946 copiedProto.clearExtension(); 947 } else { 948 copiedProto = number; 949 } 950 951 String nationalSignificantNumber = format(copiedProto, 952 PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL); 953 String[] numberGroups = NON_DIGITS_PATTERN.split(nationalSignificantNumber); 954 // The pattern will start with "+COUNTRY_CODE " so the first group will always be the empty 955 // string (before the + symbol) and the second group will be the country calling code. The third 956 // group will be area code if it is not the last group. 957 if (numberGroups.length <= 3) { 958 return 0; 959 } 960 961 if (getNumberType(number) == PhoneNumberType.MOBILE) { 962 // For example Argentinian mobile numbers, when formatted in the international format, are in 963 // the form of +54 9 NDC XXXX.... As a result, we take the length of the third group (NDC) and 964 // add the length of the second group (which is the mobile token), which also forms part of 965 // the national significant number. This assumes that the mobile token is always formatted 966 // separately from the rest of the phone number. 967 String mobileToken = getCountryMobileToken(number.getCountryCode()); 968 if (!mobileToken.equals("")) { 969 return numberGroups[2].length() + numberGroups[3].length(); 970 } 971 } 972 return numberGroups[2].length(); 973 } 974 975 /** 976 * Returns the mobile token for the provided country calling code if it has one, otherwise 977 * returns an empty string. A mobile token is a number inserted before the area code when dialing 978 * a mobile number from that country from abroad. 979 * 980 * @param countryCallingCode the country calling code for which we want the mobile token 981 * @return the mobile token, as a string, for the given country calling code 982 */ 983 public static String getCountryMobileToken(int countryCallingCode) { 984 if (MOBILE_TOKEN_MAPPINGS.containsKey(countryCallingCode)) { 985 return MOBILE_TOKEN_MAPPINGS.get(countryCallingCode); 986 } 987 return ""; 988 } 989 990 /** 991 * Normalizes a string of characters representing a phone number by replacing all characters found 992 * in the accompanying map with the values therein, and stripping all other characters if 993 * removeNonMatches is true. 994 * 995 * @param number a string of characters representing a phone number 996 * @param normalizationReplacements a mapping of characters to what they should be replaced by in 997 * the normalized version of the phone number 998 * @param removeNonMatches indicates whether characters that are not able to be replaced should 999 * be stripped from the number. If this is false, they will be left unchanged in the number. 1000 * @return the normalized string version of the phone number 1001 */ 1002 private static String normalizeHelper(CharSequence number, 1003 Map<Character, Character> normalizationReplacements, 1004 boolean removeNonMatches) { 1005 StringBuilder normalizedNumber = new StringBuilder(number.length()); 1006 for (int i = 0; i < number.length(); i++) { 1007 char character = number.charAt(i); 1008 Character newDigit = normalizationReplacements.get(Character.toUpperCase(character)); 1009 if (newDigit != null) { 1010 normalizedNumber.append(newDigit); 1011 } else if (!removeNonMatches) { 1012 normalizedNumber.append(character); 1013 } 1014 // If neither of the above are true, we remove this character. 1015 } 1016 return normalizedNumber.toString(); 1017 } 1018 1019 /** 1020 * Sets or resets the PhoneNumberUtil singleton instance. If set to null, the next call to 1021 * {@code getInstance()} will load (and return) the default instance. 1022 */ 1023 // @VisibleForTesting 1024 static synchronized void setInstance(PhoneNumberUtil util) { 1025 instance = util; 1026 } 1027 1028 /** 1029 * Returns all regions the library has metadata for. 1030 * 1031 * @return an unordered set of the two-letter region codes for every geographical region the 1032 * library supports 1033 */ 1034 public Set<String> getSupportedRegions() { 1035 return Collections.unmodifiableSet(supportedRegions); 1036 } 1037 1038 /** 1039 * Returns all global network calling codes the library has metadata for. 1040 * 1041 * @return an unordered set of the country calling codes for every non-geographical entity the 1042 * library supports 1043 */ 1044 public Set<Integer> getSupportedGlobalNetworkCallingCodes() { 1045 return Collections.unmodifiableSet(countryCodesForNonGeographicalRegion); 1046 } 1047 1048 /** 1049 * Returns all country calling codes the library has metadata for, covering both non-geographical 1050 * entities (global network calling codes) and those used for geographical entities. This could be 1051 * used to populate a drop-down box of country calling codes for a phone-number widget, for 1052 * instance. 1053 * 1054 * @return an unordered set of the country calling codes for every geographical and 1055 * non-geographical entity the library supports 1056 */ 1057 public Set<Integer> getSupportedCallingCodes() { 1058 return Collections.unmodifiableSet(countryCallingCodeToRegionCodeMap.keySet()); 1059 } 1060 1061 /** 1062 * Returns true if there is any possible number data set for a particular PhoneNumberDesc. 1063 */ 1064 private static boolean descHasPossibleNumberData(PhoneNumberDesc desc) { 1065 // If this is empty, it means numbers of this type inherit from the "general desc" -> the value 1066 // "-1" means that no numbers exist for this type. 1067 return desc.getPossibleLengthCount() != 1 || desc.getPossibleLength(0) != -1; 1068 } 1069 1070 // Note: descHasData must account for any of MetadataFilter's excludableChildFields potentially 1071 // being absent from the metadata. It must check them all. For any changes in descHasData, ensure 1072 // that all the excludableChildFields are still being checked. If your change is safe simply 1073 // mention why during a review without needing to change MetadataFilter. 1074 /** 1075 * Returns true if there is any data set for a particular PhoneNumberDesc. 1076 */ 1077 private static boolean descHasData(PhoneNumberDesc desc) { 1078 // Checking most properties since we don't know what's present, since a custom build may have 1079 // stripped just one of them (e.g. liteBuild strips exampleNumber). We don't bother checking the 1080 // possibleLengthsLocalOnly, since if this is the only thing that's present we don't really 1081 // support the type at all: no type-specific methods will work with only this data. 1082 return desc.hasExampleNumber() 1083 || descHasPossibleNumberData(desc) 1084 || desc.hasNationalNumberPattern(); 1085 } 1086 1087 /** 1088 * Returns the types we have metadata for based on the PhoneMetadata object passed in, which must 1089 * be non-null. 1090 */ 1091 private Set<PhoneNumberType> getSupportedTypesForMetadata(PhoneMetadata metadata) { 1092 Set<PhoneNumberType> types = new TreeSet<PhoneNumberType>(); 1093 for (PhoneNumberType type : PhoneNumberType.values()) { 1094 if (type == PhoneNumberType.FIXED_LINE_OR_MOBILE || type == PhoneNumberType.UNKNOWN) { 1095 // Never return FIXED_LINE_OR_MOBILE (it is a convenience type, and represents that a 1096 // particular number type can't be determined) or UNKNOWN (the non-type). 1097 continue; 1098 } 1099 if (descHasData(getNumberDescByType(metadata, type))) { 1100 types.add(type); 1101 } 1102 } 1103 return Collections.unmodifiableSet(types); 1104 } 1105 1106 /** 1107 * Returns the types for a given region which the library has metadata for. Will not include 1108 * FIXED_LINE_OR_MOBILE (if numbers in this region could be classified as FIXED_LINE_OR_MOBILE, 1109 * both FIXED_LINE and MOBILE would be present) and UNKNOWN. 1110 * 1111 * No types will be returned for invalid or unknown region codes. 1112 */ 1113 public Set<PhoneNumberType> getSupportedTypesForRegion(String regionCode) { 1114 if (!isValidRegionCode(regionCode)) { 1115 logger.log(Level.WARNING, "Invalid or unknown region code provided: " + regionCode); 1116 return Collections.unmodifiableSet(new TreeSet<PhoneNumberType>()); 1117 } 1118 PhoneMetadata metadata = getMetadataForRegion(regionCode); 1119 return getSupportedTypesForMetadata(metadata); 1120 } 1121 1122 /** 1123 * Returns the types for a country-code belonging to a non-geographical entity which the library 1124 * has metadata for. Will not include FIXED_LINE_OR_MOBILE (if numbers for this non-geographical 1125 * entity could be classified as FIXED_LINE_OR_MOBILE, both FIXED_LINE and MOBILE would be 1126 * present) and UNKNOWN. 1127 * 1128 * No types will be returned for country calling codes that do not map to a known non-geographical 1129 * entity. 1130 */ 1131 public Set<PhoneNumberType> getSupportedTypesForNonGeoEntity(int countryCallingCode) { 1132 PhoneMetadata metadata = getMetadataForNonGeographicalRegion(countryCallingCode); 1133 if (metadata == null) { 1134 logger.log(Level.WARNING, "Unknown country calling code for a non-geographical entity " 1135 + "provided: " + countryCallingCode); 1136 return Collections.unmodifiableSet(new TreeSet<PhoneNumberType>()); 1137 } 1138 return getSupportedTypesForMetadata(metadata); 1139 } 1140 1141 /** 1142 * Gets a {@link PhoneNumberUtil} instance to carry out international phone number formatting, 1143 * parsing, or validation. The instance is loaded with all phone number metadata. 1144 * 1145 * <p>The {@link PhoneNumberUtil} is implemented as a singleton. Therefore, calling getInstance 1146 * multiple times will only result in one instance being created. 1147 * 1148 * @return a PhoneNumberUtil instance 1149 */ 1150 public static synchronized PhoneNumberUtil getInstance() { 1151 if (instance == null) { 1152 setInstance(createInstance(MetadataManager.DEFAULT_METADATA_LOADER)); 1153 } 1154 return instance; 1155 } 1156 1157 /** 1158 * Create a new {@link PhoneNumberUtil} instance to carry out international phone number 1159 * formatting, parsing, or validation. The instance is loaded with all metadata by 1160 * using the metadataLoader specified. 1161 * 1162 * <p>This method should only be used in the rare case in which you want to manage your own 1163 * metadata loading. Calling this method multiple times is very expensive, as each time 1164 * a new instance is created from scratch. When in doubt, use {@link #getInstance}. 1165 * 1166 * @param metadataLoader customized metadata loader. This should not be null 1167 * @return a PhoneNumberUtil instance 1168 */ 1169 public static PhoneNumberUtil createInstance(MetadataLoader metadataLoader) { 1170 if (metadataLoader == null) { 1171 throw new IllegalArgumentException("metadataLoader could not be null."); 1172 } 1173 return createInstance(new MultiFileMetadataSourceImpl(metadataLoader)); 1174 } 1175 1176 /** 1177 * Create a new {@link PhoneNumberUtil} instance to carry out international phone number 1178 * formatting, parsing, or validation. The instance is loaded with all metadata by 1179 * using the metadataSource specified. 1180 * 1181 * <p>This method should only be used in the rare case in which you want to manage your own 1182 * metadata loading. Calling this method multiple times is very expensive, as each time 1183 * a new instance is created from scratch. When in doubt, use {@link #getInstance}. 1184 * 1185 * @param metadataSource customized metadata source. This should not be null 1186 * @return a PhoneNumberUtil instance 1187 */ 1188 private static PhoneNumberUtil createInstance(MetadataSource metadataSource) { 1189 if (metadataSource == null) { 1190 throw new IllegalArgumentException("metadataSource could not be null."); 1191 } 1192 return new PhoneNumberUtil(metadataSource, 1193 CountryCodeToRegionCodeMap.getCountryCodeToRegionCodeMap()); 1194 } 1195 1196 /** 1197 * Helper function to check if the national prefix formatting rule has the first group only, i.e., 1198 * does not start with the national prefix. 1199 */ 1200 static boolean formattingRuleHasFirstGroupOnly(String nationalPrefixFormattingRule) { 1201 return nationalPrefixFormattingRule.length() == 0 1202 || FIRST_GROUP_ONLY_PREFIX_PATTERN.matcher(nationalPrefixFormattingRule).matches(); 1203 } 1204 1205 /** 1206 * Tests whether a phone number has a geographical association. It checks if the number is 1207 * associated with a certain region in the country to which it belongs. Note that this doesn't 1208 * verify if the number is actually in use. 1209 */ 1210 public boolean isNumberGeographical(PhoneNumber phoneNumber) { 1211 return isNumberGeographical(getNumberType(phoneNumber), phoneNumber.getCountryCode()); 1212 } 1213 1214 /** 1215 * Overload of isNumberGeographical(PhoneNumber), since calculating the phone number type is 1216 * expensive; if we have already done this, we don't want to do it again. 1217 */ 1218 public boolean isNumberGeographical(PhoneNumberType phoneNumberType, int countryCallingCode) { 1219 return phoneNumberType == PhoneNumberType.FIXED_LINE 1220 || phoneNumberType == PhoneNumberType.FIXED_LINE_OR_MOBILE 1221 || (GEO_MOBILE_COUNTRIES.contains(countryCallingCode) 1222 && phoneNumberType == PhoneNumberType.MOBILE); 1223 } 1224 1225 /** 1226 * Helper function to check region code is not unknown or null. 1227 */ 1228 private boolean isValidRegionCode(String regionCode) { 1229 return regionCode != null && supportedRegions.contains(regionCode); 1230 } 1231 1232 /** 1233 * Helper function to check the country calling code is valid. 1234 */ 1235 private boolean hasValidCountryCallingCode(int countryCallingCode) { 1236 return countryCallingCodeToRegionCodeMap.containsKey(countryCallingCode); 1237 } 1238 1239 /** 1240 * Formats a phone number in the specified format using default rules. Note that this does not 1241 * promise to produce a phone number that the user can dial from where they are - although we do 1242 * format in either 'national' or 'international' format depending on what the client asks for, we 1243 * do not currently support a more abbreviated format, such as for users in the same "area" who 1244 * could potentially dial the number without area code. Note that if the phone number has a 1245 * country calling code of 0 or an otherwise invalid country calling code, we cannot work out 1246 * which formatting rules to apply so we return the national significant number with no formatting 1247 * applied. 1248 * 1249 * @param number the phone number to be formatted 1250 * @param numberFormat the format the phone number should be formatted into 1251 * @return the formatted phone number 1252 */ 1253 public String format(PhoneNumber number, PhoneNumberFormat numberFormat) { 1254 if (number.getNationalNumber() == 0 && number.hasRawInput()) { 1255 // Unparseable numbers that kept their raw input just use that. 1256 // This is the only case where a number can be formatted as E164 without a 1257 // leading '+' symbol (but the original number wasn't parseable anyway). 1258 // TODO: Consider removing the 'if' above so that unparseable 1259 // strings without raw input format to the empty string instead of "+00". 1260 String rawInput = number.getRawInput(); 1261 if (rawInput.length() > 0) { 1262 return rawInput; 1263 } 1264 } 1265 StringBuilder formattedNumber = new StringBuilder(20); 1266 format(number, numberFormat, formattedNumber); 1267 return formattedNumber.toString(); 1268 } 1269 1270 /** 1271 * Same as {@link #format(PhoneNumber, PhoneNumberFormat)}, but accepts a mutable StringBuilder as 1272 * a parameter to decrease object creation when invoked many times. 1273 */ 1274 public void format(PhoneNumber number, PhoneNumberFormat numberFormat, 1275 StringBuilder formattedNumber) { 1276 // Clear the StringBuilder first. 1277 formattedNumber.setLength(0); 1278 int countryCallingCode = number.getCountryCode(); 1279 String nationalSignificantNumber = getNationalSignificantNumber(number); 1280 1281 if (numberFormat == PhoneNumberFormat.E164) { 1282 // Early exit for E164 case (even if the country calling code is invalid) since no formatting 1283 // of the national number needs to be applied. Extensions are not formatted. 1284 formattedNumber.append(nationalSignificantNumber); 1285 prefixNumberWithCountryCallingCode(countryCallingCode, PhoneNumberFormat.E164, 1286 formattedNumber); 1287 return; 1288 } 1289 if (!hasValidCountryCallingCode(countryCallingCode)) { 1290 formattedNumber.append(nationalSignificantNumber); 1291 return; 1292 } 1293 // Note getRegionCodeForCountryCode() is used because formatting information for regions which 1294 // share a country calling code is contained by only one region for performance reasons. For 1295 // example, for NANPA regions it will be contained in the metadata for US. 1296 String regionCode = getRegionCodeForCountryCode(countryCallingCode); 1297 // Metadata cannot be null because the country calling code is valid (which means that the 1298 // region code cannot be ZZ and must be one of our supported region codes). 1299 PhoneMetadata metadata = 1300 getMetadataForRegionOrCallingCode(countryCallingCode, regionCode); 1301 formattedNumber.append(formatNsn(nationalSignificantNumber, metadata, numberFormat)); 1302 maybeAppendFormattedExtension(number, metadata, numberFormat, formattedNumber); 1303 prefixNumberWithCountryCallingCode(countryCallingCode, numberFormat, formattedNumber); 1304 } 1305 1306 /** 1307 * Formats a phone number in the specified format using client-defined formatting rules. Note that 1308 * if the phone number has a country calling code of zero or an otherwise invalid country calling 1309 * code, we cannot work out things like whether there should be a national prefix applied, or how 1310 * to format extensions, so we return the national significant number with no formatting applied. 1311 * 1312 * @param number the phone number to be formatted 1313 * @param numberFormat the format the phone number should be formatted into 1314 * @param userDefinedFormats formatting rules specified by clients 1315 * @return the formatted phone number 1316 */ 1317 public String formatByPattern(PhoneNumber number, 1318 PhoneNumberFormat numberFormat, 1319 List<NumberFormat> userDefinedFormats) { 1320 int countryCallingCode = number.getCountryCode(); 1321 String nationalSignificantNumber = getNationalSignificantNumber(number); 1322 if (!hasValidCountryCallingCode(countryCallingCode)) { 1323 return nationalSignificantNumber; 1324 } 1325 // Note getRegionCodeForCountryCode() is used because formatting information for regions which 1326 // share a country calling code is contained by only one region for performance reasons. For 1327 // example, for NANPA regions it will be contained in the metadata for US. 1328 String regionCode = getRegionCodeForCountryCode(countryCallingCode); 1329 // Metadata cannot be null because the country calling code is valid. 1330 PhoneMetadata metadata = 1331 getMetadataForRegionOrCallingCode(countryCallingCode, regionCode); 1332 1333 StringBuilder formattedNumber = new StringBuilder(20); 1334 1335 NumberFormat formattingPattern = 1336 chooseFormattingPatternForNumber(userDefinedFormats, nationalSignificantNumber); 1337 if (formattingPattern == null) { 1338 // If no pattern above is matched, we format the number as a whole. 1339 formattedNumber.append(nationalSignificantNumber); 1340 } else { 1341 NumberFormat.Builder numFormatCopy = NumberFormat.newBuilder(); 1342 // Before we do a replacement of the national prefix pattern $NP with the national prefix, we 1343 // need to copy the rule so that subsequent replacements for different numbers have the 1344 // appropriate national prefix. 1345 numFormatCopy.mergeFrom(formattingPattern); 1346 String nationalPrefixFormattingRule = formattingPattern.getNationalPrefixFormattingRule(); 1347 if (nationalPrefixFormattingRule.length() > 0) { 1348 String nationalPrefix = metadata.getNationalPrefix(); 1349 if (nationalPrefix.length() > 0) { 1350 // Replace $NP with national prefix and $FG with the first group ($1). 1351 nationalPrefixFormattingRule = 1352 nationalPrefixFormattingRule.replace(NP_STRING, nationalPrefix); 1353 nationalPrefixFormattingRule = nationalPrefixFormattingRule.replace(FG_STRING, "$1"); 1354 numFormatCopy.setNationalPrefixFormattingRule(nationalPrefixFormattingRule); 1355 } else { 1356 // We don't want to have a rule for how to format the national prefix if there isn't one. 1357 numFormatCopy.clearNationalPrefixFormattingRule(); 1358 } 1359 } 1360 formattedNumber.append( 1361 formatNsnUsingPattern(nationalSignificantNumber, numFormatCopy.build(), numberFormat)); 1362 } 1363 maybeAppendFormattedExtension(number, metadata, numberFormat, formattedNumber); 1364 prefixNumberWithCountryCallingCode(countryCallingCode, numberFormat, formattedNumber); 1365 return formattedNumber.toString(); 1366 } 1367 1368 /** 1369 * Formats a phone number in national format for dialing using the carrier as specified in the 1370 * {@code carrierCode}. The {@code carrierCode} will always be used regardless of whether the 1371 * phone number already has a preferred domestic carrier code stored. If {@code carrierCode} 1372 * contains an empty string, returns the number in national format without any carrier code. 1373 * 1374 * @param number the phone number to be formatted 1375 * @param carrierCode the carrier selection code to be used 1376 * @return the formatted phone number in national format for dialing using the carrier as 1377 * specified in the {@code carrierCode} 1378 */ 1379 public String formatNationalNumberWithCarrierCode(PhoneNumber number, CharSequence carrierCode) { 1380 int countryCallingCode = number.getCountryCode(); 1381 String nationalSignificantNumber = getNationalSignificantNumber(number); 1382 if (!hasValidCountryCallingCode(countryCallingCode)) { 1383 return nationalSignificantNumber; 1384 } 1385 1386 // Note getRegionCodeForCountryCode() is used because formatting information for regions which 1387 // share a country calling code is contained by only one region for performance reasons. For 1388 // example, for NANPA regions it will be contained in the metadata for US. 1389 String regionCode = getRegionCodeForCountryCode(countryCallingCode); 1390 // Metadata cannot be null because the country calling code is valid. 1391 PhoneMetadata metadata = getMetadataForRegionOrCallingCode(countryCallingCode, regionCode); 1392 1393 StringBuilder formattedNumber = new StringBuilder(20); 1394 formattedNumber.append(formatNsn(nationalSignificantNumber, metadata, 1395 PhoneNumberFormat.NATIONAL, carrierCode)); 1396 maybeAppendFormattedExtension(number, metadata, PhoneNumberFormat.NATIONAL, formattedNumber); 1397 prefixNumberWithCountryCallingCode(countryCallingCode, PhoneNumberFormat.NATIONAL, 1398 formattedNumber); 1399 return formattedNumber.toString(); 1400 } 1401 1402 private PhoneMetadata getMetadataForRegionOrCallingCode( 1403 int countryCallingCode, String regionCode) { 1404 return REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCode) 1405 ? getMetadataForNonGeographicalRegion(countryCallingCode) 1406 : getMetadataForRegion(regionCode); 1407 } 1408 1409 /** 1410 * Formats a phone number in national format for dialing using the carrier as specified in the 1411 * preferredDomesticCarrierCode field of the PhoneNumber object passed in. If that is missing, 1412 * use the {@code fallbackCarrierCode} passed in instead. If there is no 1413 * {@code preferredDomesticCarrierCode}, and the {@code fallbackCarrierCode} contains an empty 1414 * string, return the number in national format without any carrier code. 1415 * 1416 * <p>Use {@link #formatNationalNumberWithCarrierCode} instead if the carrier code passed in 1417 * should take precedence over the number's {@code preferredDomesticCarrierCode} when formatting. 1418 * 1419 * @param number the phone number to be formatted 1420 * @param fallbackCarrierCode the carrier selection code to be used, if none is found in the 1421 * phone number itself 1422 * @return the formatted phone number in national format for dialing using the number's 1423 * {@code preferredDomesticCarrierCode}, or the {@code fallbackCarrierCode} passed in if 1424 * none is found 1425 */ 1426 public String formatNationalNumberWithPreferredCarrierCode(PhoneNumber number, 1427 CharSequence fallbackCarrierCode) { 1428 return formatNationalNumberWithCarrierCode(number, 1429 // Historically, we set this to an empty string when parsing with raw input if none was 1430 // found in the input string. However, this doesn't result in a number we can dial. For this 1431 // reason, we treat the empty string the same as if it isn't set at all. 1432 number.getPreferredDomesticCarrierCode().length() > 0 1433 ? number.getPreferredDomesticCarrierCode() 1434 : fallbackCarrierCode); 1435 } 1436 1437 /** 1438 * Returns a number formatted in such a way that it can be dialed from a mobile phone in a 1439 * specific region. If the number cannot be reached from the region (e.g. some countries block 1440 * toll-free numbers from being called outside of the country), the method returns an empty 1441 * string. 1442 * 1443 * @param number the phone number to be formatted 1444 * @param regionCallingFrom the region where the call is being placed 1445 * @param withFormatting whether the number should be returned with formatting symbols, such as 1446 * spaces and dashes. 1447 * @return the formatted phone number 1448 */ 1449 public String formatNumberForMobileDialing(PhoneNumber number, String regionCallingFrom, 1450 boolean withFormatting) { 1451 int countryCallingCode = number.getCountryCode(); 1452 if (!hasValidCountryCallingCode(countryCallingCode)) { 1453 return number.hasRawInput() ? number.getRawInput() : ""; 1454 } 1455 1456 String formattedNumber = ""; 1457 // Clear the extension, as that part cannot normally be dialed together with the main number. 1458 PhoneNumber numberNoExt = new PhoneNumber().mergeFrom(number).clearExtension(); 1459 String regionCode = getRegionCodeForCountryCode(countryCallingCode); 1460 PhoneNumberType numberType = getNumberType(numberNoExt); 1461 boolean isValidNumber = (numberType != PhoneNumberType.UNKNOWN); 1462 if (regionCallingFrom.equals(regionCode)) { 1463 boolean isFixedLineOrMobile = 1464 (numberType == PhoneNumberType.FIXED_LINE) || (numberType == PhoneNumberType.MOBILE) 1465 || (numberType == PhoneNumberType.FIXED_LINE_OR_MOBILE); 1466 // Carrier codes may be needed in some countries. We handle this here. 1467 if (regionCode.equals("CO") && numberType == PhoneNumberType.FIXED_LINE) { 1468 formattedNumber = 1469 formatNationalNumberWithCarrierCode(numberNoExt, COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX); 1470 } else if (regionCode.equals("BR") && isFixedLineOrMobile) { 1471 // Historically, we set this to an empty string when parsing with raw input if none was 1472 // found in the input string. However, this doesn't result in a number we can dial. For this 1473 // reason, we treat the empty string the same as if it isn't set at all. 1474 formattedNumber = numberNoExt.getPreferredDomesticCarrierCode().length() > 0 1475 ? formattedNumber = formatNationalNumberWithPreferredCarrierCode(numberNoExt, "") 1476 // Brazilian fixed line and mobile numbers need to be dialed with a carrier code when 1477 // called within Brazil. Without that, most of the carriers won't connect the call. 1478 // Because of that, we return an empty string here. 1479 : ""; 1480 } else if (countryCallingCode == NANPA_COUNTRY_CODE) { 1481 // For NANPA countries, we output international format for numbers that can be dialed 1482 // internationally, since that always works, except for numbers which might potentially be 1483 // short numbers, which are always dialled in national format. 1484 PhoneMetadata regionMetadata = getMetadataForRegion(regionCallingFrom); 1485 if (canBeInternationallyDialled(numberNoExt) 1486 && testNumberLength(getNationalSignificantNumber(numberNoExt), regionMetadata) 1487 != ValidationResult.TOO_SHORT) { 1488 formattedNumber = format(numberNoExt, PhoneNumberFormat.INTERNATIONAL); 1489 } else { 1490 formattedNumber = format(numberNoExt, PhoneNumberFormat.NATIONAL); 1491 } 1492 } else { 1493 // For non-geographical countries, and Mexican, Chilean, and Uzbek fixed line and mobile 1494 // numbers, we output international format for numbers that can be dialed internationally as 1495 // that always works. 1496 if ((regionCode.equals(REGION_CODE_FOR_NON_GEO_ENTITY) 1497 // MX fixed line and mobile numbers should always be formatted in international format, 1498 // even when dialed within MX. For national format to work, a carrier code needs to be 1499 // used, and the correct carrier code depends on if the caller and callee are from the 1500 // same local area. It is trickier to get that to work correctly than using 1501 // international format, which is tested to work fine on all carriers. 1502 // CL fixed line numbers need the national prefix when dialing in the national format, 1503 // but don't have it when used for display. The reverse is true for mobile numbers. As 1504 // a result, we output them in the international format to make it work. 1505 // UZ mobile and fixed-line numbers have to be formatted in international format or 1506 // prefixed with special codes like 03, 04 (for fixed-line) and 05 (for mobile) for 1507 // dialling successfully from mobile devices. As we do not have complete information on 1508 // special codes and to be consistent with formatting across all phone types we return 1509 // the number in international format here. 1510 || ((regionCode.equals("MX") || regionCode.equals("CL") 1511 || regionCode.equals("UZ")) && isFixedLineOrMobile)) 1512 && canBeInternationallyDialled(numberNoExt)) { 1513 formattedNumber = format(numberNoExt, PhoneNumberFormat.INTERNATIONAL); 1514 } else { 1515 formattedNumber = format(numberNoExt, PhoneNumberFormat.NATIONAL); 1516 } 1517 } 1518 } else if (isValidNumber && canBeInternationallyDialled(numberNoExt)) { 1519 // We assume that short numbers are not diallable from outside their region, so if a number 1520 // is not a valid regular length phone number, we treat it as if it cannot be internationally 1521 // dialled. 1522 return withFormatting ? format(numberNoExt, PhoneNumberFormat.INTERNATIONAL) 1523 : format(numberNoExt, PhoneNumberFormat.E164); 1524 } 1525 return withFormatting ? formattedNumber 1526 : normalizeDiallableCharsOnly(formattedNumber); 1527 } 1528 1529 /** 1530 * Formats a phone number for out-of-country dialing purposes. If no regionCallingFrom is 1531 * supplied, we format the number in its INTERNATIONAL format. If the country calling code is the 1532 * same as that of the region where the number is from, then NATIONAL formatting will be applied. 1533 * 1534 * <p>If the number itself has a country calling code of zero or an otherwise invalid country 1535 * calling code, then we return the number with no formatting applied. 1536 * 1537 * <p>Note this function takes care of the case for calling inside of NANPA and between Russia and 1538 * Kazakhstan (who share the same country calling code). In those cases, no international prefix 1539 * is used. For regions which have multiple international prefixes, the number in its 1540 * INTERNATIONAL format will be returned instead. 1541 * 1542 * @param number the phone number to be formatted 1543 * @param regionCallingFrom the region where the call is being placed 1544 * @return the formatted phone number 1545 */ 1546 public String formatOutOfCountryCallingNumber(PhoneNumber number, 1547 String regionCallingFrom) { 1548 if (!isValidRegionCode(regionCallingFrom)) { 1549 logger.log(Level.WARNING, 1550 "Trying to format number from invalid region " 1551 + regionCallingFrom 1552 + ". International formatting applied."); 1553 return format(number, PhoneNumberFormat.INTERNATIONAL); 1554 } 1555 int countryCallingCode = number.getCountryCode(); 1556 String nationalSignificantNumber = getNationalSignificantNumber(number); 1557 if (!hasValidCountryCallingCode(countryCallingCode)) { 1558 return nationalSignificantNumber; 1559 } 1560 if (countryCallingCode == NANPA_COUNTRY_CODE) { 1561 if (isNANPACountry(regionCallingFrom)) { 1562 // For NANPA regions, return the national format for these regions but prefix it with the 1563 // country calling code. 1564 return countryCallingCode + " " + format(number, PhoneNumberFormat.NATIONAL); 1565 } 1566 } else if (countryCallingCode == getCountryCodeForValidRegion(regionCallingFrom)) { 1567 // If regions share a country calling code, the country calling code need not be dialled. 1568 // This also applies when dialling within a region, so this if clause covers both these cases. 1569 // Technically this is the case for dialling from La Reunion to other overseas departments of 1570 // France (French Guiana, Martinique, Guadeloupe), but not vice versa - so we don't cover this 1571 // edge case for now and for those cases return the version including country calling code. 1572 // Details here: http://www.petitfute.com/voyage/225-info-pratiques-reunion 1573 return format(number, PhoneNumberFormat.NATIONAL); 1574 } 1575 // Metadata cannot be null because we checked 'isValidRegionCode()' above. 1576 PhoneMetadata metadataForRegionCallingFrom = getMetadataForRegion(regionCallingFrom); 1577 String internationalPrefix = metadataForRegionCallingFrom.getInternationalPrefix(); 1578 1579 // In general, if there is a preferred international prefix, use that. Otherwise, for regions 1580 // that have multiple international prefixes, the international format of the number is 1581 // returned since we would not know which one to use. 1582 String internationalPrefixForFormatting = ""; 1583 if (metadataForRegionCallingFrom.hasPreferredInternationalPrefix()) { 1584 internationalPrefixForFormatting = 1585 metadataForRegionCallingFrom.getPreferredInternationalPrefix(); 1586 } else if (SINGLE_INTERNATIONAL_PREFIX.matcher(internationalPrefix).matches()) { 1587 internationalPrefixForFormatting = internationalPrefix; 1588 } 1589 1590 String regionCode = getRegionCodeForCountryCode(countryCallingCode); 1591 // Metadata cannot be null because the country calling code is valid. 1592 PhoneMetadata metadataForRegion = 1593 getMetadataForRegionOrCallingCode(countryCallingCode, regionCode); 1594 String formattedNationalNumber = 1595 formatNsn(nationalSignificantNumber, metadataForRegion, PhoneNumberFormat.INTERNATIONAL); 1596 StringBuilder formattedNumber = new StringBuilder(formattedNationalNumber); 1597 maybeAppendFormattedExtension(number, metadataForRegion, PhoneNumberFormat.INTERNATIONAL, 1598 formattedNumber); 1599 if (internationalPrefixForFormatting.length() > 0) { 1600 formattedNumber.insert(0, " ").insert(0, countryCallingCode).insert(0, " ") 1601 .insert(0, internationalPrefixForFormatting); 1602 } else { 1603 prefixNumberWithCountryCallingCode(countryCallingCode, 1604 PhoneNumberFormat.INTERNATIONAL, 1605 formattedNumber); 1606 } 1607 return formattedNumber.toString(); 1608 } 1609 1610 /** 1611 * Formats a phone number using the original phone number format that the number is parsed from. 1612 * The original format is embedded in the country_code_source field of the PhoneNumber object 1613 * passed in. If such information is missing, the number will be formatted into the NATIONAL 1614 * format by default. When we don't have a formatting pattern for the number, the method returns 1615 * the raw input when it is available. 1616 * 1617 * Note this method guarantees no digit will be inserted, removed or modified as a result of 1618 * formatting. 1619 * 1620 * @param number the phone number that needs to be formatted in its original number format 1621 * @param regionCallingFrom the region whose IDD needs to be prefixed if the original number 1622 * has one 1623 * @return the formatted phone number in its original number format 1624 */ 1625 public String formatInOriginalFormat(PhoneNumber number, String regionCallingFrom) { 1626 if (number.hasRawInput() && !hasFormattingPatternForNumber(number)) { 1627 // We check if we have the formatting pattern because without that, we might format the number 1628 // as a group without national prefix. 1629 return number.getRawInput(); 1630 } 1631 if (!number.hasCountryCodeSource()) { 1632 return format(number, PhoneNumberFormat.NATIONAL); 1633 } 1634 String formattedNumber; 1635 switch (number.getCountryCodeSource()) { 1636 case FROM_NUMBER_WITH_PLUS_SIGN: 1637 formattedNumber = format(number, PhoneNumberFormat.INTERNATIONAL); 1638 break; 1639 case FROM_NUMBER_WITH_IDD: 1640 formattedNumber = formatOutOfCountryCallingNumber(number, regionCallingFrom); 1641 break; 1642 case FROM_NUMBER_WITHOUT_PLUS_SIGN: 1643 formattedNumber = format(number, PhoneNumberFormat.INTERNATIONAL).substring(1); 1644 break; 1645 case FROM_DEFAULT_COUNTRY: 1646 // Fall-through to default case. 1647 default: 1648 String regionCode = getRegionCodeForCountryCode(number.getCountryCode()); 1649 // We strip non-digits from the NDD here, and from the raw input later, so that we can 1650 // compare them easily. 1651 String nationalPrefix = getNddPrefixForRegion(regionCode, true /* strip non-digits */); 1652 String nationalFormat = format(number, PhoneNumberFormat.NATIONAL); 1653 if (nationalPrefix == null || nationalPrefix.length() == 0) { 1654 // If the region doesn't have a national prefix at all, we can safely return the national 1655 // format without worrying about a national prefix being added. 1656 formattedNumber = nationalFormat; 1657 break; 1658 } 1659 // Otherwise, we check if the original number was entered with a national prefix. 1660 if (rawInputContainsNationalPrefix( 1661 number.getRawInput(), nationalPrefix, regionCode)) { 1662 // If so, we can safely return the national format. 1663 formattedNumber = nationalFormat; 1664 break; 1665 } 1666 // Metadata cannot be null here because getNddPrefixForRegion() (above) returns null if 1667 // there is no metadata for the region. 1668 PhoneMetadata metadata = getMetadataForRegion(regionCode); 1669 String nationalNumber = getNationalSignificantNumber(number); 1670 NumberFormat formatRule = 1671 chooseFormattingPatternForNumber(metadata.getNumberFormatList(), nationalNumber); 1672 // The format rule could still be null here if the national number was 0 and there was no 1673 // raw input (this should not be possible for numbers generated by the phonenumber library 1674 // as they would also not have a country calling code and we would have exited earlier). 1675 if (formatRule == null) { 1676 formattedNumber = nationalFormat; 1677 break; 1678 } 1679 // When the format we apply to this number doesn't contain national prefix, we can just 1680 // return the national format. 1681 // TODO: Refactor the code below with the code in 1682 // isNationalPrefixPresentIfRequired. 1683 String candidateNationalPrefixRule = formatRule.getNationalPrefixFormattingRule(); 1684 // We assume that the first-group symbol will never be _before_ the national prefix. 1685 int indexOfFirstGroup = candidateNationalPrefixRule.indexOf("$1"); 1686 if (indexOfFirstGroup <= 0) { 1687 formattedNumber = nationalFormat; 1688 break; 1689 } 1690 candidateNationalPrefixRule = 1691 candidateNationalPrefixRule.substring(0, indexOfFirstGroup); 1692 candidateNationalPrefixRule = normalizeDigitsOnly(candidateNationalPrefixRule); 1693 if (candidateNationalPrefixRule.length() == 0) { 1694 // National prefix not used when formatting this number. 1695 formattedNumber = nationalFormat; 1696 break; 1697 } 1698 // Otherwise, we need to remove the national prefix from our output. 1699 NumberFormat.Builder numFormatCopy = NumberFormat.newBuilder(); 1700 numFormatCopy.mergeFrom(formatRule); 1701 numFormatCopy.clearNationalPrefixFormattingRule(); 1702 List<NumberFormat> numberFormats = new ArrayList<NumberFormat>(1); 1703 numberFormats.add(numFormatCopy.build()); 1704 formattedNumber = formatByPattern(number, PhoneNumberFormat.NATIONAL, numberFormats); 1705 break; 1706 } 1707 String rawInput = number.getRawInput(); 1708 // If no digit is inserted/removed/modified as a result of our formatting, we return the 1709 // formatted phone number; otherwise we return the raw input the user entered. 1710 if (formattedNumber != null && rawInput.length() > 0) { 1711 String normalizedFormattedNumber = normalizeDiallableCharsOnly(formattedNumber); 1712 String normalizedRawInput = normalizeDiallableCharsOnly(rawInput); 1713 if (!normalizedFormattedNumber.equals(normalizedRawInput)) { 1714 formattedNumber = rawInput; 1715 } 1716 } 1717 return formattedNumber; 1718 } 1719 1720 // Check if rawInput, which is assumed to be in the national format, has a national prefix. The 1721 // national prefix is assumed to be in digits-only form. 1722 private boolean rawInputContainsNationalPrefix(String rawInput, String nationalPrefix, 1723 String regionCode) { 1724 String normalizedNationalNumber = normalizeDigitsOnly(rawInput); 1725 if (normalizedNationalNumber.startsWith(nationalPrefix)) { 1726 try { 1727 // Some Japanese numbers (e.g. 00777123) might be mistaken to contain the national prefix 1728 // when written without it (e.g. 0777123) if we just do prefix matching. To tackle that, we 1729 // check the validity of the number if the assumed national prefix is removed (777123 won't 1730 // be valid in Japan). 1731 return isValidNumber( 1732 parse(normalizedNationalNumber.substring(nationalPrefix.length()), regionCode)); 1733 } catch (NumberParseException e) { 1734 return false; 1735 } 1736 } 1737 return false; 1738 } 1739 1740 private boolean hasFormattingPatternForNumber(PhoneNumber number) { 1741 int countryCallingCode = number.getCountryCode(); 1742 String phoneNumberRegion = getRegionCodeForCountryCode(countryCallingCode); 1743 PhoneMetadata metadata = 1744 getMetadataForRegionOrCallingCode(countryCallingCode, phoneNumberRegion); 1745 if (metadata == null) { 1746 return false; 1747 } 1748 String nationalNumber = getNationalSignificantNumber(number); 1749 NumberFormat formatRule = 1750 chooseFormattingPatternForNumber(metadata.getNumberFormatList(), nationalNumber); 1751 return formatRule != null; 1752 } 1753 1754 /** 1755 * Formats a phone number for out-of-country dialing purposes. 1756 * 1757 * Note that in this version, if the number was entered originally using alpha characters and 1758 * this version of the number is stored in raw_input, this representation of the number will be 1759 * used rather than the digit representation. Grouping information, as specified by characters 1760 * such as "-" and " ", will be retained. 1761 * 1762 * <p><b>Caveats:</b></p> 1763 * <ul> 1764 * <li> This will not produce good results if the country calling code is both present in the raw 1765 * input _and_ is the start of the national number. This is not a problem in the regions 1766 * which typically use alpha numbers. 1767 * <li> This will also not produce good results if the raw input has any grouping information 1768 * within the first three digits of the national number, and if the function needs to strip 1769 * preceding digits/words in the raw input before these digits. Normally people group the 1770 * first three digits together so this is not a huge problem - and will be fixed if it 1771 * proves to be so. 1772 * </ul> 1773 * 1774 * @param number the phone number that needs to be formatted 1775 * @param regionCallingFrom the region where the call is being placed 1776 * @return the formatted phone number 1777 */ 1778 public String formatOutOfCountryKeepingAlphaChars(PhoneNumber number, 1779 String regionCallingFrom) { 1780 String rawInput = number.getRawInput(); 1781 // If there is no raw input, then we can't keep alpha characters because there aren't any. 1782 // In this case, we return formatOutOfCountryCallingNumber. 1783 if (rawInput.length() == 0) { 1784 return formatOutOfCountryCallingNumber(number, regionCallingFrom); 1785 } 1786 int countryCode = number.getCountryCode(); 1787 if (!hasValidCountryCallingCode(countryCode)) { 1788 return rawInput; 1789 } 1790 // Strip any prefix such as country calling code, IDD, that was present. We do this by comparing 1791 // the number in raw_input with the parsed number. 1792 // To do this, first we normalize punctuation. We retain number grouping symbols such as " " 1793 // only. 1794 rawInput = normalizeHelper(rawInput, ALL_PLUS_NUMBER_GROUPING_SYMBOLS, true); 1795 // Now we trim everything before the first three digits in the parsed number. We choose three 1796 // because all valid alpha numbers have 3 digits at the start - if it does not, then we don't 1797 // trim anything at all. Similarly, if the national number was less than three digits, we don't 1798 // trim anything at all. 1799 String nationalNumber = getNationalSignificantNumber(number); 1800 if (nationalNumber.length() > 3) { 1801 int firstNationalNumberDigit = rawInput.indexOf(nationalNumber.substring(0, 3)); 1802 if (firstNationalNumberDigit != -1) { 1803 rawInput = rawInput.substring(firstNationalNumberDigit); 1804 } 1805 } 1806 PhoneMetadata metadataForRegionCallingFrom = getMetadataForRegion(regionCallingFrom); 1807 if (countryCode == NANPA_COUNTRY_CODE) { 1808 if (isNANPACountry(regionCallingFrom)) { 1809 return countryCode + " " + rawInput; 1810 } 1811 } else if (metadataForRegionCallingFrom != null 1812 && countryCode == getCountryCodeForValidRegion(regionCallingFrom)) { 1813 NumberFormat formattingPattern = 1814 chooseFormattingPatternForNumber(metadataForRegionCallingFrom.getNumberFormatList(), 1815 nationalNumber); 1816 if (formattingPattern == null) { 1817 // If no pattern above is matched, we format the original input. 1818 return rawInput; 1819 } 1820 NumberFormat.Builder newFormat = NumberFormat.newBuilder(); 1821 newFormat.mergeFrom(formattingPattern); 1822 // The first group is the first group of digits that the user wrote together. 1823 newFormat.setPattern("(\\d+)(.*)"); 1824 // Here we just concatenate them back together after the national prefix has been fixed. 1825 newFormat.setFormat("$1$2"); 1826 // Now we format using this pattern instead of the default pattern, but with the national 1827 // prefix prefixed if necessary. 1828 // This will not work in the cases where the pattern (and not the leading digits) decide 1829 // whether a national prefix needs to be used, since we have overridden the pattern to match 1830 // anything, but that is not the case in the metadata to date. 1831 return formatNsnUsingPattern(rawInput, newFormat.build(), PhoneNumberFormat.NATIONAL); 1832 } 1833 String internationalPrefixForFormatting = ""; 1834 // If an unsupported region-calling-from is entered, or a country with multiple international 1835 // prefixes, the international format of the number is returned, unless there is a preferred 1836 // international prefix. 1837 if (metadataForRegionCallingFrom != null) { 1838 String internationalPrefix = metadataForRegionCallingFrom.getInternationalPrefix(); 1839 internationalPrefixForFormatting = 1840 SINGLE_INTERNATIONAL_PREFIX.matcher(internationalPrefix).matches() 1841 ? internationalPrefix 1842 : metadataForRegionCallingFrom.getPreferredInternationalPrefix(); 1843 } 1844 StringBuilder formattedNumber = new StringBuilder(rawInput); 1845 String regionCode = getRegionCodeForCountryCode(countryCode); 1846 // Metadata cannot be null because the country calling code is valid. 1847 PhoneMetadata metadataForRegion = getMetadataForRegionOrCallingCode(countryCode, regionCode); 1848 maybeAppendFormattedExtension(number, metadataForRegion, 1849 PhoneNumberFormat.INTERNATIONAL, formattedNumber); 1850 if (internationalPrefixForFormatting.length() > 0) { 1851 formattedNumber.insert(0, " ").insert(0, countryCode).insert(0, " ") 1852 .insert(0, internationalPrefixForFormatting); 1853 } else { 1854 // Invalid region entered as country-calling-from (so no metadata was found for it) or the 1855 // region chosen has multiple international dialling prefixes. 1856 if (!isValidRegionCode(regionCallingFrom)) { 1857 logger.log(Level.WARNING, 1858 "Trying to format number from invalid region " 1859 + regionCallingFrom 1860 + ". International formatting applied."); 1861 } 1862 prefixNumberWithCountryCallingCode(countryCode, 1863 PhoneNumberFormat.INTERNATIONAL, 1864 formattedNumber); 1865 } 1866 return formattedNumber.toString(); 1867 } 1868 1869 /** 1870 * Gets the national significant number of a phone number. Note a national significant number 1871 * doesn't contain a national prefix or any formatting. 1872 * 1873 * @param number the phone number for which the national significant number is needed 1874 * @return the national significant number of the PhoneNumber object passed in 1875 */ 1876 public String getNationalSignificantNumber(PhoneNumber number) { 1877 // If leading zero(s) have been set, we prefix this now. Note this is not a national prefix. 1878 StringBuilder nationalNumber = new StringBuilder(); 1879 if (number.isItalianLeadingZero() && number.getNumberOfLeadingZeros() > 0) { 1880 char[] zeros = new char[number.getNumberOfLeadingZeros()]; 1881 Arrays.fill(zeros, '0'); 1882 nationalNumber.append(new String(zeros)); 1883 } 1884 nationalNumber.append(number.getNationalNumber()); 1885 return nationalNumber.toString(); 1886 } 1887 1888 /** 1889 * A helper function that is used by format and formatByPattern. 1890 */ 1891 private void prefixNumberWithCountryCallingCode(int countryCallingCode, 1892 PhoneNumberFormat numberFormat, 1893 StringBuilder formattedNumber) { 1894 switch (numberFormat) { 1895 case E164: 1896 formattedNumber.insert(0, countryCallingCode).insert(0, PLUS_SIGN); 1897 return; 1898 case INTERNATIONAL: 1899 formattedNumber.insert(0, " ").insert(0, countryCallingCode).insert(0, PLUS_SIGN); 1900 return; 1901 case RFC3966: 1902 formattedNumber.insert(0, "-").insert(0, countryCallingCode).insert(0, PLUS_SIGN) 1903 .insert(0, RFC3966_PREFIX); 1904 return; 1905 case NATIONAL: 1906 default: 1907 return; 1908 } 1909 } 1910 1911 // Simple wrapper of formatNsn for the common case of no carrier code. 1912 private String formatNsn(String number, PhoneMetadata metadata, PhoneNumberFormat numberFormat) { 1913 return formatNsn(number, metadata, numberFormat, null); 1914 } 1915 1916 // Note in some regions, the national number can be written in two completely different ways 1917 // depending on whether it forms part of the NATIONAL format or INTERNATIONAL format. The 1918 // numberFormat parameter here is used to specify which format to use for those cases. If a 1919 // carrierCode is specified, this will be inserted into the formatted string to replace $CC. 1920 private String formatNsn(String number, 1921 PhoneMetadata metadata, 1922 PhoneNumberFormat numberFormat, 1923 CharSequence carrierCode) { 1924 List<NumberFormat> intlNumberFormats = metadata.getIntlNumberFormatList(); 1925 // When the intlNumberFormats exists, we use that to format national number for the 1926 // INTERNATIONAL format instead of using the numberDesc.numberFormats. 1927 List<NumberFormat> availableFormats = 1928 (intlNumberFormats.size() == 0 || numberFormat == PhoneNumberFormat.NATIONAL) 1929 ? metadata.getNumberFormatList() 1930 : metadata.getIntlNumberFormatList(); 1931 NumberFormat formattingPattern = chooseFormattingPatternForNumber(availableFormats, number); 1932 return (formattingPattern == null) 1933 ? number 1934 : formatNsnUsingPattern(number, formattingPattern, numberFormat, carrierCode); 1935 } 1936 1937 NumberFormat chooseFormattingPatternForNumber(List<NumberFormat> availableFormats, 1938 String nationalNumber) { 1939 for (NumberFormat numFormat : availableFormats) { 1940 int size = numFormat.getLeadingDigitsPatternCount(); 1941 if (size == 0 || regexCache.getPatternForRegex( 1942 // We always use the last leading_digits_pattern, as it is the most detailed. 1943 numFormat.getLeadingDigitsPattern(size - 1)).matcher(nationalNumber).lookingAt()) { 1944 Matcher m = regexCache.getPatternForRegex(numFormat.getPattern()).matcher(nationalNumber); 1945 if (m.matches()) { 1946 return numFormat; 1947 } 1948 } 1949 } 1950 return null; 1951 } 1952 1953 // Simple wrapper of formatNsnUsingPattern for the common case of no carrier code. 1954 String formatNsnUsingPattern(String nationalNumber, 1955 NumberFormat formattingPattern, 1956 PhoneNumberFormat numberFormat) { 1957 return formatNsnUsingPattern(nationalNumber, formattingPattern, numberFormat, null); 1958 } 1959 1960 // Note that carrierCode is optional - if null or an empty string, no carrier code replacement 1961 // will take place. 1962 private String formatNsnUsingPattern(String nationalNumber, 1963 NumberFormat formattingPattern, 1964 PhoneNumberFormat numberFormat, 1965 CharSequence carrierCode) { 1966 String numberFormatRule = formattingPattern.getFormat(); 1967 Matcher m = 1968 regexCache.getPatternForRegex(formattingPattern.getPattern()).matcher(nationalNumber); 1969 String formattedNationalNumber = ""; 1970 if (numberFormat == PhoneNumberFormat.NATIONAL 1971 && carrierCode != null && carrierCode.length() > 0 1972 && formattingPattern.getDomesticCarrierCodeFormattingRule().length() > 0) { 1973 // Replace the $CC in the formatting rule with the desired carrier code. 1974 String carrierCodeFormattingRule = formattingPattern.getDomesticCarrierCodeFormattingRule(); 1975 carrierCodeFormattingRule = carrierCodeFormattingRule.replace(CC_STRING, carrierCode); 1976 // Now replace the $FG in the formatting rule with the first group and the carrier code 1977 // combined in the appropriate way. 1978 numberFormatRule = FIRST_GROUP_PATTERN.matcher(numberFormatRule) 1979 .replaceFirst(carrierCodeFormattingRule); 1980 formattedNationalNumber = m.replaceAll(numberFormatRule); 1981 } else { 1982 // Use the national prefix formatting rule instead. 1983 String nationalPrefixFormattingRule = formattingPattern.getNationalPrefixFormattingRule(); 1984 if (numberFormat == PhoneNumberFormat.NATIONAL 1985 && nationalPrefixFormattingRule != null 1986 && nationalPrefixFormattingRule.length() > 0) { 1987 Matcher firstGroupMatcher = FIRST_GROUP_PATTERN.matcher(numberFormatRule); 1988 formattedNationalNumber = 1989 m.replaceAll(firstGroupMatcher.replaceFirst(nationalPrefixFormattingRule)); 1990 } else { 1991 formattedNationalNumber = m.replaceAll(numberFormatRule); 1992 } 1993 } 1994 if (numberFormat == PhoneNumberFormat.RFC3966) { 1995 // Strip any leading punctuation. 1996 Matcher matcher = SEPARATOR_PATTERN.matcher(formattedNationalNumber); 1997 if (matcher.lookingAt()) { 1998 formattedNationalNumber = matcher.replaceFirst(""); 1999 } 2000 // Replace the rest with a dash between each number group. 2001 formattedNationalNumber = matcher.reset(formattedNationalNumber).replaceAll("-"); 2002 } 2003 return formattedNationalNumber; 2004 } 2005 2006 /** 2007 * Gets a valid number for the specified region. 2008 * 2009 * @param regionCode the region for which an example number is needed 2010 * @return a valid fixed-line number for the specified region. Returns null when the metadata 2011 * does not contain such information, or the region 001 is passed in. For 001 (representing 2012 * non-geographical numbers), call {@link #getExampleNumberForNonGeoEntity} instead. 2013 */ 2014 public PhoneNumber getExampleNumber(String regionCode) { 2015 return getExampleNumberForType(regionCode, PhoneNumberType.FIXED_LINE); 2016 } 2017 2018 /** 2019 * Gets an invalid number for the specified region. This is useful for unit-testing purposes, 2020 * where you want to test what will happen with an invalid number. Note that the number that is 2021 * returned will always be able to be parsed and will have the correct country code. It may also 2022 * be a valid *short* number/code for this region. Validity checking such numbers is handled with 2023 * {@link com.google.i18n.phonenumbers.ShortNumberInfo}. 2024 * 2025 * @param regionCode the region for which an example number is needed 2026 * @return an invalid number for the specified region. Returns null when an unsupported region or 2027 * the region 001 (Earth) is passed in. 2028 */ 2029 public PhoneNumber getInvalidExampleNumber(String regionCode) { 2030 if (!isValidRegionCode(regionCode)) { 2031 logger.log(Level.WARNING, "Invalid or unknown region code provided: " + regionCode); 2032 return null; 2033 } 2034 // We start off with a valid fixed-line number since every country supports this. Alternatively 2035 // we could start with a different number type, since fixed-line numbers typically have a wide 2036 // breadth of valid number lengths and we may have to make it very short before we get an 2037 // invalid number. 2038 PhoneNumberDesc desc = getNumberDescByType(getMetadataForRegion(regionCode), 2039 PhoneNumberType.FIXED_LINE); 2040 if (!desc.hasExampleNumber()) { 2041 // This shouldn't happen; we have a test for this. 2042 return null; 2043 } 2044 String exampleNumber = desc.getExampleNumber(); 2045 // Try and make the number invalid. We do this by changing the length. We try reducing the 2046 // length of the number, since currently no region has a number that is the same length as 2047 // MIN_LENGTH_FOR_NSN. This is probably quicker than making the number longer, which is another 2048 // alternative. We could also use the possible number pattern to extract the possible lengths of 2049 // the number to make this faster, but this method is only for unit-testing so simplicity is 2050 // preferred to performance. We don't want to return a number that can't be parsed, so we check 2051 // the number is long enough. We try all possible lengths because phone number plans often have 2052 // overlapping prefixes so the number 123456 might be valid as a fixed-line number, and 12345 as 2053 // a mobile number. It would be faster to loop in a different order, but we prefer numbers that 2054 // look closer to real numbers (and it gives us a variety of different lengths for the resulting 2055 // phone numbers - otherwise they would all be MIN_LENGTH_FOR_NSN digits long.) 2056 for (int phoneNumberLength = exampleNumber.length() - 1; 2057 phoneNumberLength >= MIN_LENGTH_FOR_NSN; 2058 phoneNumberLength--) { 2059 String numberToTry = exampleNumber.substring(0, phoneNumberLength); 2060 try { 2061 PhoneNumber possiblyValidNumber = parse(numberToTry, regionCode); 2062 if (!isValidNumber(possiblyValidNumber)) { 2063 return possiblyValidNumber; 2064 } 2065 } catch (NumberParseException e) { 2066 // Shouldn't happen: we have already checked the length, we know example numbers have 2067 // only valid digits, and we know the region code is fine. 2068 } 2069 } 2070 // We have a test to check that this doesn't happen for any of our supported regions. 2071 return null; 2072 } 2073 2074 /** 2075 * Gets a valid number for the specified region and number type. 2076 * 2077 * @param regionCode the region for which an example number is needed 2078 * @param type the type of number that is needed 2079 * @return a valid number for the specified region and type. Returns null when the metadata 2080 * does not contain such information or if an invalid region or region 001 was entered. 2081 * For 001 (representing non-geographical numbers), call 2082 * {@link #getExampleNumberForNonGeoEntity} instead. 2083 */ 2084 public PhoneNumber getExampleNumberForType(String regionCode, PhoneNumberType type) { 2085 // Check the region code is valid. 2086 if (!isValidRegionCode(regionCode)) { 2087 logger.log(Level.WARNING, "Invalid or unknown region code provided: " + regionCode); 2088 return null; 2089 } 2090 PhoneNumberDesc desc = getNumberDescByType(getMetadataForRegion(regionCode), type); 2091 try { 2092 if (desc.hasExampleNumber()) { 2093 return parse(desc.getExampleNumber(), regionCode); 2094 } 2095 } catch (NumberParseException e) { 2096 logger.log(Level.SEVERE, e.toString()); 2097 } 2098 return null; 2099 } 2100 2101 /** 2102 * Gets a valid number for the specified number type (it may belong to any country). 2103 * 2104 * @param type the type of number that is needed 2105 * @return a valid number for the specified type. Returns null when the metadata 2106 * does not contain such information. This should only happen when no numbers of this type are 2107 * allocated anywhere in the world anymore. 2108 */ 2109 public PhoneNumber getExampleNumberForType(PhoneNumberType type) { 2110 for (String regionCode : getSupportedRegions()) { 2111 PhoneNumber exampleNumber = getExampleNumberForType(regionCode, type); 2112 if (exampleNumber != null) { 2113 return exampleNumber; 2114 } 2115 } 2116 // If there wasn't an example number for a region, try the non-geographical entities. 2117 for (int countryCallingCode : getSupportedGlobalNetworkCallingCodes()) { 2118 PhoneNumberDesc desc = getNumberDescByType( 2119 getMetadataForNonGeographicalRegion(countryCallingCode), type); 2120 try { 2121 if (desc.hasExampleNumber()) { 2122 return parse("+" + countryCallingCode + desc.getExampleNumber(), UNKNOWN_REGION); 2123 } 2124 } catch (NumberParseException e) { 2125 logger.log(Level.SEVERE, e.toString()); 2126 } 2127 } 2128 // There are no example numbers of this type for any country in the library. 2129 return null; 2130 } 2131 2132 /** 2133 * Gets a valid number for the specified country calling code for a non-geographical entity. 2134 * 2135 * @param countryCallingCode the country calling code for a non-geographical entity 2136 * @return a valid number for the non-geographical entity. Returns null when the metadata 2137 * does not contain such information, or the country calling code passed in does not belong 2138 * to a non-geographical entity. 2139 */ 2140 public PhoneNumber getExampleNumberForNonGeoEntity(int countryCallingCode) { 2141 PhoneMetadata metadata = getMetadataForNonGeographicalRegion(countryCallingCode); 2142 if (metadata != null) { 2143 // For geographical entities, fixed-line data is always present. However, for non-geographical 2144 // entities, this is not the case, so we have to go through different types to find the 2145 // example number. We don't check fixed-line or personal number since they aren't used by 2146 // non-geographical entities (if this changes, a unit-test will catch this.) 2147 for (PhoneNumberDesc desc : Arrays.asList(metadata.getMobile(), metadata.getTollFree(), 2148 metadata.getSharedCost(), metadata.getVoip(), metadata.getVoicemail(), 2149 metadata.getUan(), metadata.getPremiumRate())) { 2150 try { 2151 if (desc != null && desc.hasExampleNumber()) { 2152 return parse("+" + countryCallingCode + desc.getExampleNumber(), UNKNOWN_REGION); 2153 } 2154 } catch (NumberParseException e) { 2155 logger.log(Level.SEVERE, e.toString()); 2156 } 2157 } 2158 } else { 2159 logger.log(Level.WARNING, 2160 "Invalid or unknown country calling code provided: " + countryCallingCode); 2161 } 2162 return null; 2163 } 2164 2165 /** 2166 * Appends the formatted extension of a phone number to formattedNumber, if the phone number had 2167 * an extension specified. 2168 */ 2169 private void maybeAppendFormattedExtension(PhoneNumber number, PhoneMetadata metadata, 2170 PhoneNumberFormat numberFormat, 2171 StringBuilder formattedNumber) { 2172 if (number.hasExtension() && number.getExtension().length() > 0) { 2173 if (numberFormat == PhoneNumberFormat.RFC3966) { 2174 formattedNumber.append(RFC3966_EXTN_PREFIX).append(number.getExtension()); 2175 } else { 2176 if (metadata.hasPreferredExtnPrefix()) { 2177 formattedNumber.append(metadata.getPreferredExtnPrefix()).append(number.getExtension()); 2178 } else { 2179 formattedNumber.append(DEFAULT_EXTN_PREFIX).append(number.getExtension()); 2180 } 2181 } 2182 } 2183 } 2184 2185 PhoneNumberDesc getNumberDescByType(PhoneMetadata metadata, PhoneNumberType type) { 2186 switch (type) { 2187 case PREMIUM_RATE: 2188 return metadata.getPremiumRate(); 2189 case TOLL_FREE: 2190 return metadata.getTollFree(); 2191 case MOBILE: 2192 return metadata.getMobile(); 2193 case FIXED_LINE: 2194 case FIXED_LINE_OR_MOBILE: 2195 return metadata.getFixedLine(); 2196 case SHARED_COST: 2197 return metadata.getSharedCost(); 2198 case VOIP: 2199 return metadata.getVoip(); 2200 case PERSONAL_NUMBER: 2201 return metadata.getPersonalNumber(); 2202 case PAGER: 2203 return metadata.getPager(); 2204 case UAN: 2205 return metadata.getUan(); 2206 case VOICEMAIL: 2207 return metadata.getVoicemail(); 2208 default: 2209 return metadata.getGeneralDesc(); 2210 } 2211 } 2212 2213 /** 2214 * Gets the type of a valid phone number. 2215 * 2216 * @param number the phone number that we want to know the type 2217 * @return the type of the phone number, or UNKNOWN if it is invalid 2218 */ 2219 public PhoneNumberType getNumberType(PhoneNumber number) { 2220 String regionCode = getRegionCodeForNumber(number); 2221 PhoneMetadata metadata = getMetadataForRegionOrCallingCode(number.getCountryCode(), regionCode); 2222 if (metadata == null) { 2223 return PhoneNumberType.UNKNOWN; 2224 } 2225 String nationalSignificantNumber = getNationalSignificantNumber(number); 2226 return getNumberTypeHelper(nationalSignificantNumber, metadata); 2227 } 2228 2229 private PhoneNumberType getNumberTypeHelper(String nationalNumber, PhoneMetadata metadata) { 2230 if (!isNumberMatchingDesc(nationalNumber, metadata.getGeneralDesc())) { 2231 return PhoneNumberType.UNKNOWN; 2232 } 2233 2234 if (isNumberMatchingDesc(nationalNumber, metadata.getPremiumRate())) { 2235 return PhoneNumberType.PREMIUM_RATE; 2236 } 2237 if (isNumberMatchingDesc(nationalNumber, metadata.getTollFree())) { 2238 return PhoneNumberType.TOLL_FREE; 2239 } 2240 if (isNumberMatchingDesc(nationalNumber, metadata.getSharedCost())) { 2241 return PhoneNumberType.SHARED_COST; 2242 } 2243 if (isNumberMatchingDesc(nationalNumber, metadata.getVoip())) { 2244 return PhoneNumberType.VOIP; 2245 } 2246 if (isNumberMatchingDesc(nationalNumber, metadata.getPersonalNumber())) { 2247 return PhoneNumberType.PERSONAL_NUMBER; 2248 } 2249 if (isNumberMatchingDesc(nationalNumber, metadata.getPager())) { 2250 return PhoneNumberType.PAGER; 2251 } 2252 if (isNumberMatchingDesc(nationalNumber, metadata.getUan())) { 2253 return PhoneNumberType.UAN; 2254 } 2255 if (isNumberMatchingDesc(nationalNumber, metadata.getVoicemail())) { 2256 return PhoneNumberType.VOICEMAIL; 2257 } 2258 2259 boolean isFixedLine = isNumberMatchingDesc(nationalNumber, metadata.getFixedLine()); 2260 if (isFixedLine) { 2261 if (metadata.getSameMobileAndFixedLinePattern()) { 2262 return PhoneNumberType.FIXED_LINE_OR_MOBILE; 2263 } else if (isNumberMatchingDesc(nationalNumber, metadata.getMobile())) { 2264 return PhoneNumberType.FIXED_LINE_OR_MOBILE; 2265 } 2266 return PhoneNumberType.FIXED_LINE; 2267 } 2268 // Otherwise, test to see if the number is mobile. Only do this if certain that the patterns for 2269 // mobile and fixed line aren't the same. 2270 if (!metadata.getSameMobileAndFixedLinePattern() 2271 && isNumberMatchingDesc(nationalNumber, metadata.getMobile())) { 2272 return PhoneNumberType.MOBILE; 2273 } 2274 return PhoneNumberType.UNKNOWN; 2275 } 2276 2277 /** 2278 * Returns the metadata for the given region code or {@code null} if the region code is invalid 2279 * or unknown. 2280 */ 2281 PhoneMetadata getMetadataForRegion(String regionCode) { 2282 if (!isValidRegionCode(regionCode)) { 2283 return null; 2284 } 2285 return metadataSource.getMetadataForRegion(regionCode); 2286 } 2287 2288 PhoneMetadata getMetadataForNonGeographicalRegion(int countryCallingCode) { 2289 if (!countryCallingCodeToRegionCodeMap.containsKey(countryCallingCode)) { 2290 return null; 2291 } 2292 return metadataSource.getMetadataForNonGeographicalRegion(countryCallingCode); 2293 } 2294 2295 boolean isNumberMatchingDesc(String nationalNumber, PhoneNumberDesc numberDesc) { 2296 // Check if any possible number lengths are present; if so, we use them to avoid checking the 2297 // validation pattern if they don't match. If they are absent, this means they match the general 2298 // description, which we have already checked before checking a specific number type. 2299 int actualLength = nationalNumber.length(); 2300 List<Integer> possibleLengths = numberDesc.getPossibleLengthList(); 2301 if (possibleLengths.size() > 0 && !possibleLengths.contains(actualLength)) { 2302 return false; 2303 } 2304 return matcherApi.matchNationalNumber(nationalNumber, numberDesc, false); 2305 } 2306 2307 /** 2308 * Tests whether a phone number matches a valid pattern. Note this doesn't verify the number 2309 * is actually in use, which is impossible to tell by just looking at a number itself. It only 2310 * verifies whether the parsed, canonicalised number is valid: not whether a particular series of 2311 * digits entered by the user is diallable from the region provided when parsing. For example, the 2312 * number +41 (0) 78 927 2696 can be parsed into a number with country code "41" and national 2313 * significant number "789272696". This is valid, while the original string is not diallable. 2314 * 2315 * @param number the phone number that we want to validate 2316 * @return a boolean that indicates whether the number is of a valid pattern 2317 */ 2318 public boolean isValidNumber(PhoneNumber number) { 2319 String regionCode = getRegionCodeForNumber(number); 2320 return isValidNumberForRegion(number, regionCode); 2321 } 2322 2323 /** 2324 * Tests whether a phone number is valid for a certain region. Note this doesn't verify the number 2325 * is actually in use, which is impossible to tell by just looking at a number itself. If the 2326 * country calling code is not the same as the country calling code for the region, this 2327 * immediately exits with false. After this, the specific number pattern rules for the region are 2328 * examined. This is useful for determining for example whether a particular number is valid for 2329 * Canada, rather than just a valid NANPA number. 2330 * Warning: In most cases, you want to use {@link #isValidNumber} instead. For example, this 2331 * method will mark numbers from British Crown dependencies such as the Isle of Man as invalid for 2332 * the region "GB" (United Kingdom), since it has its own region code, "IM", which may be 2333 * undesirable. 2334 * 2335 * @param number the phone number that we want to validate 2336 * @param regionCode the region that we want to validate the phone number for 2337 * @return a boolean that indicates whether the number is of a valid pattern 2338 */ 2339 public boolean isValidNumberForRegion(PhoneNumber number, String regionCode) { 2340 int countryCode = number.getCountryCode(); 2341 PhoneMetadata metadata = getMetadataForRegionOrCallingCode(countryCode, regionCode); 2342 if ((metadata == null) 2343 || (!REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCode) 2344 && countryCode != getCountryCodeForValidRegion(regionCode))) { 2345 // Either the region code was invalid, or the country calling code for this number does not 2346 // match that of the region code. 2347 return false; 2348 } 2349 String nationalSignificantNumber = getNationalSignificantNumber(number); 2350 return getNumberTypeHelper(nationalSignificantNumber, metadata) != PhoneNumberType.UNKNOWN; 2351 } 2352 2353 /** 2354 * Returns the region where a phone number is from. This could be used for geocoding at the region 2355 * level. Only guarantees correct results for valid, full numbers (not short-codes, or invalid 2356 * numbers). 2357 * 2358 * @param number the phone number whose origin we want to know 2359 * @return the region where the phone number is from, or null if no region matches this calling 2360 * code 2361 */ 2362 public String getRegionCodeForNumber(PhoneNumber number) { 2363 int countryCode = number.getCountryCode(); 2364 List<String> regions = countryCallingCodeToRegionCodeMap.get(countryCode); 2365 if (regions == null) { 2366 logger.log(Level.INFO, "Missing/invalid country_code (" + countryCode + ")"); 2367 return null; 2368 } 2369 if (regions.size() == 1) { 2370 return regions.get(0); 2371 } else { 2372 return getRegionCodeForNumberFromRegionList(number, regions); 2373 } 2374 } 2375 2376 private String getRegionCodeForNumberFromRegionList(PhoneNumber number, 2377 List<String> regionCodes) { 2378 String nationalNumber = getNationalSignificantNumber(number); 2379 for (String regionCode : regionCodes) { 2380 // If leadingDigits is present, use this. Otherwise, do full validation. 2381 // Metadata cannot be null because the region codes come from the country calling code map. 2382 PhoneMetadata metadata = getMetadataForRegion(regionCode); 2383 if (metadata.hasLeadingDigits()) { 2384 if (regexCache.getPatternForRegex(metadata.getLeadingDigits()) 2385 .matcher(nationalNumber).lookingAt()) { 2386 return regionCode; 2387 } 2388 } else if (getNumberTypeHelper(nationalNumber, metadata) != PhoneNumberType.UNKNOWN) { 2389 return regionCode; 2390 } 2391 } 2392 return null; 2393 } 2394 2395 /** 2396 * Returns the region code that matches the specific country calling code. In the case of no 2397 * region code being found, ZZ will be returned. In the case of multiple regions, the one 2398 * designated in the metadata as the "main" region for this calling code will be returned. If the 2399 * countryCallingCode entered is valid but doesn't match a specific region (such as in the case of 2400 * non-geographical calling codes like 800) the value "001" will be returned (corresponding to 2401 * the value for World in the UN M.49 schema). 2402 */ 2403 public String getRegionCodeForCountryCode(int countryCallingCode) { 2404 List<String> regionCodes = countryCallingCodeToRegionCodeMap.get(countryCallingCode); 2405 return regionCodes == null ? UNKNOWN_REGION : regionCodes.get(0); 2406 } 2407 2408 /** 2409 * Returns a list with the region codes that match the specific country calling code. For 2410 * non-geographical country calling codes, the region code 001 is returned. Also, in the case 2411 * of no region code being found, an empty list is returned. 2412 */ 2413 public List<String> getRegionCodesForCountryCode(int countryCallingCode) { 2414 List<String> regionCodes = countryCallingCodeToRegionCodeMap.get(countryCallingCode); 2415 return Collections.unmodifiableList(regionCodes == null ? new ArrayList<String>(0) 2416 : regionCodes); 2417 } 2418 2419 /** 2420 * Returns the country calling code for a specific region. For example, this would be 1 for the 2421 * United States, and 64 for New Zealand. 2422 * 2423 * @param regionCode the region that we want to get the country calling code for 2424 * @return the country calling code for the region denoted by regionCode 2425 */ 2426 public int getCountryCodeForRegion(String regionCode) { 2427 if (!isValidRegionCode(regionCode)) { 2428 logger.log(Level.WARNING, 2429 "Invalid or missing region code (" 2430 + ((regionCode == null) ? "null" : regionCode) 2431 + ") provided."); 2432 return 0; 2433 } 2434 return getCountryCodeForValidRegion(regionCode); 2435 } 2436 2437 /** 2438 * Returns the country calling code for a specific region. For example, this would be 1 for the 2439 * United States, and 64 for New Zealand. Assumes the region is already valid. 2440 * 2441 * @param regionCode the region that we want to get the country calling code for 2442 * @return the country calling code for the region denoted by regionCode 2443 * @throws IllegalArgumentException if the region is invalid 2444 */ 2445 private int getCountryCodeForValidRegion(String regionCode) { 2446 PhoneMetadata metadata = getMetadataForRegion(regionCode); 2447 if (metadata == null) { 2448 throw new IllegalArgumentException("Invalid region code: " + regionCode); 2449 } 2450 return metadata.getCountryCode(); 2451 } 2452 2453 /** 2454 * Returns the national dialling prefix for a specific region. For example, this would be 1 for 2455 * the United States, and 0 for New Zealand. Set stripNonDigits to true to strip symbols like "~" 2456 * (which indicates a wait for a dialling tone) from the prefix returned. If no national prefix is 2457 * present, we return null. 2458 * 2459 * <p>Warning: Do not use this method for do-your-own formatting - for some regions, the 2460 * national dialling prefix is used only for certain types of numbers. Use the library's 2461 * formatting functions to prefix the national prefix when required. 2462 * 2463 * @param regionCode the region that we want to get the dialling prefix for 2464 * @param stripNonDigits true to strip non-digits from the national dialling prefix 2465 * @return the dialling prefix for the region denoted by regionCode 2466 */ 2467 public String getNddPrefixForRegion(String regionCode, boolean stripNonDigits) { 2468 PhoneMetadata metadata = getMetadataForRegion(regionCode); 2469 if (metadata == null) { 2470 logger.log(Level.WARNING, 2471 "Invalid or missing region code (" 2472 + ((regionCode == null) ? "null" : regionCode) 2473 + ") provided."); 2474 return null; 2475 } 2476 String nationalPrefix = metadata.getNationalPrefix(); 2477 // If no national prefix was found, we return null. 2478 if (nationalPrefix.length() == 0) { 2479 return null; 2480 } 2481 if (stripNonDigits) { 2482 // Note: if any other non-numeric symbols are ever used in national prefixes, these would have 2483 // to be removed here as well. 2484 nationalPrefix = nationalPrefix.replace("~", ""); 2485 } 2486 return nationalPrefix; 2487 } 2488 2489 /** 2490 * Checks if this is a region under the North American Numbering Plan Administration (NANPA). 2491 * 2492 * @return true if regionCode is one of the regions under NANPA 2493 */ 2494 public boolean isNANPACountry(String regionCode) { 2495 return nanpaRegions.contains(regionCode); 2496 } 2497 2498 /** 2499 * Checks if the number is a valid vanity (alpha) number such as 800 MICROSOFT. A valid vanity 2500 * number will start with at least 3 digits and will have three or more alpha characters. This 2501 * does not do region-specific checks - to work out if this number is actually valid for a region, 2502 * it should be parsed and methods such as {@link #isPossibleNumberWithReason} and 2503 * {@link #isValidNumber} should be used. 2504 * 2505 * @param number the number that needs to be checked 2506 * @return true if the number is a valid vanity number 2507 */ 2508 public boolean isAlphaNumber(CharSequence number) { 2509 if (!isViablePhoneNumber(number)) { 2510 // Number is too short, or doesn't match the basic phone number pattern. 2511 return false; 2512 } 2513 StringBuilder strippedNumber = new StringBuilder(number); 2514 maybeStripExtension(strippedNumber); 2515 return VALID_ALPHA_PHONE_PATTERN.matcher(strippedNumber).matches(); 2516 } 2517 2518 /** 2519 * Convenience wrapper around {@link #isPossibleNumberWithReason}. Instead of returning the reason 2520 * for failure, this method returns true if the number is either a possible fully-qualified number 2521 * (containing the area code and country code), or if the number could be a possible local number 2522 * (with a country code, but missing an area code). Local numbers are considered possible if they 2523 * could be possibly dialled in this format: if the area code is needed for a call to connect, the 2524 * number is not considered possible without it. 2525 * 2526 * @param number the number that needs to be checked 2527 * @return true if the number is possible 2528 */ 2529 public boolean isPossibleNumber(PhoneNumber number) { 2530 ValidationResult result = isPossibleNumberWithReason(number); 2531 return result == ValidationResult.IS_POSSIBLE 2532 || result == ValidationResult.IS_POSSIBLE_LOCAL_ONLY; 2533 } 2534 2535 /** 2536 * Convenience wrapper around {@link #isPossibleNumberForTypeWithReason}. Instead of returning the 2537 * reason for failure, this method returns true if the number is either a possible fully-qualified 2538 * number (containing the area code and country code), or if the number could be a possible local 2539 * number (with a country code, but missing an area code). Local numbers are considered possible 2540 * if they could be possibly dialled in this format: if the area code is needed for a call to 2541 * connect, the number is not considered possible without it. 2542 * 2543 * @param number the number that needs to be checked 2544 * @param type the type we are interested in 2545 * @return true if the number is possible for this particular type 2546 */ 2547 public boolean isPossibleNumberForType(PhoneNumber number, PhoneNumberType type) { 2548 ValidationResult result = isPossibleNumberForTypeWithReason(number, type); 2549 return result == ValidationResult.IS_POSSIBLE 2550 || result == ValidationResult.IS_POSSIBLE_LOCAL_ONLY; 2551 } 2552 2553 /** 2554 * Helper method to check a number against possible lengths for this region, based on the metadata 2555 * being passed in, and determine whether it matches, or is too short or too long. 2556 */ 2557 private ValidationResult testNumberLength(CharSequence number, PhoneMetadata metadata) { 2558 return testNumberLength(number, metadata, PhoneNumberType.UNKNOWN); 2559 } 2560 2561 /** 2562 * Helper method to check a number against possible lengths for this number type, and determine 2563 * whether it matches, or is too short or too long. 2564 */ 2565 private ValidationResult testNumberLength( 2566 CharSequence number, PhoneMetadata metadata, PhoneNumberType type) { 2567 PhoneNumberDesc descForType = getNumberDescByType(metadata, type); 2568 // There should always be "possibleLengths" set for every element. This is declared in the XML 2569 // schema which is verified by PhoneNumberMetadataSchemaTest. 2570 // For size efficiency, where a sub-description (e.g. fixed-line) has the same possibleLengths 2571 // as the parent, this is missing, so we fall back to the general desc (where no numbers of the 2572 // type exist at all, there is one possible length (-1) which is guaranteed not to match the 2573 // length of any real phone number). 2574 List<Integer> possibleLengths = descForType.getPossibleLengthList().isEmpty() 2575 ? metadata.getGeneralDesc().getPossibleLengthList() : descForType.getPossibleLengthList(); 2576 2577 List<Integer> localLengths = descForType.getPossibleLengthLocalOnlyList(); 2578 2579 if (type == PhoneNumberType.FIXED_LINE_OR_MOBILE) { 2580 if (!descHasPossibleNumberData(getNumberDescByType(metadata, PhoneNumberType.FIXED_LINE))) { 2581 // The rare case has been encountered where no fixedLine data is available (true for some 2582 // non-geographical entities), so we just check mobile. 2583 return testNumberLength(number, metadata, PhoneNumberType.MOBILE); 2584 } else { 2585 PhoneNumberDesc mobileDesc = getNumberDescByType(metadata, PhoneNumberType.MOBILE); 2586 if (descHasPossibleNumberData(mobileDesc)) { 2587 // Merge the mobile data in if there was any. We have to make a copy to do this. 2588 possibleLengths = new ArrayList<Integer>(possibleLengths); 2589 // Note that when adding the possible lengths from mobile, we have to again check they 2590 // aren't empty since if they are this indicates they are the same as the general desc and 2591 // should be obtained from there. 2592 possibleLengths.addAll(mobileDesc.getPossibleLengthCount() == 0 2593 ? metadata.getGeneralDesc().getPossibleLengthList() 2594 : mobileDesc.getPossibleLengthList()); 2595 // The current list is sorted; we need to merge in the new list and re-sort (duplicates 2596 // are okay). Sorting isn't so expensive because the lists are very small. 2597 Collections.sort(possibleLengths); 2598 2599 if (localLengths.isEmpty()) { 2600 localLengths = mobileDesc.getPossibleLengthLocalOnlyList(); 2601 } else { 2602 localLengths = new ArrayList<Integer>(localLengths); 2603 localLengths.addAll(mobileDesc.getPossibleLengthLocalOnlyList()); 2604 Collections.sort(localLengths); 2605 } 2606 } 2607 } 2608 } 2609 2610 // If the type is not supported at all (indicated by the possible lengths containing -1 at this 2611 // point) we return invalid length. 2612 if (possibleLengths.get(0) == -1) { 2613 return ValidationResult.INVALID_LENGTH; 2614 } 2615 2616 int actualLength = number.length(); 2617 // This is safe because there is never an overlap beween the possible lengths and the local-only 2618 // lengths; this is checked at build time. 2619 if (localLengths.contains(actualLength)) { 2620 return ValidationResult.IS_POSSIBLE_LOCAL_ONLY; 2621 } 2622 2623 int minimumLength = possibleLengths.get(0); 2624 if (minimumLength == actualLength) { 2625 return ValidationResult.IS_POSSIBLE; 2626 } else if (minimumLength > actualLength) { 2627 return ValidationResult.TOO_SHORT; 2628 } else if (possibleLengths.get(possibleLengths.size() - 1) < actualLength) { 2629 return ValidationResult.TOO_LONG; 2630 } 2631 // We skip the first element; we've already checked it. 2632 return possibleLengths.subList(1, possibleLengths.size()).contains(actualLength) 2633 ? ValidationResult.IS_POSSIBLE : ValidationResult.INVALID_LENGTH; 2634 } 2635 2636 /** 2637 * Check whether a phone number is a possible number. It provides a more lenient check than 2638 * {@link #isValidNumber} in the following sense: 2639 * <ol> 2640 * <li> It only checks the length of phone numbers. In particular, it doesn't check starting 2641 * digits of the number. 2642 * <li> It doesn't attempt to figure out the type of the number, but uses general rules which 2643 * applies to all types of phone numbers in a region. Therefore, it is much faster than 2644 * isValidNumber. 2645 * <li> For some numbers (particularly fixed-line), many regions have the concept of area code, 2646 * which together with subscriber number constitute the national significant number. It is 2647 * sometimes okay to dial only the subscriber number when dialing in the same area. This 2648 * function will return IS_POSSIBLE_LOCAL_ONLY if the subscriber-number-only version is 2649 * passed in. On the other hand, because isValidNumber validates using information on both 2650 * starting digits (for fixed line numbers, that would most likely be area codes) and 2651 * length (obviously includes the length of area codes for fixed line numbers), it will 2652 * return false for the subscriber-number-only version. 2653 * </ol> 2654 * @param number the number that needs to be checked 2655 * @return a ValidationResult object which indicates whether the number is possible 2656 */ 2657 public ValidationResult isPossibleNumberWithReason(PhoneNumber number) { 2658 return isPossibleNumberForTypeWithReason(number, PhoneNumberType.UNKNOWN); 2659 } 2660 2661 /** 2662 * Check whether a phone number is a possible number of a particular type. For types that don't 2663 * exist in a particular region, this will return a result that isn't so useful; it is recommended 2664 * that you use {@link #getSupportedTypesForRegion} or {@link #getSupportedTypesForNonGeoEntity} 2665 * respectively before calling this method to determine whether you should call it for this number 2666 * at all. 2667 * 2668 * This provides a more lenient check than {@link #isValidNumber} in the following sense: 2669 * 2670 * <ol> 2671 * <li> It only checks the length of phone numbers. In particular, it doesn't check starting 2672 * digits of the number. 2673 * <li> For some numbers (particularly fixed-line), many regions have the concept of area code, 2674 * which together with subscriber number constitute the national significant number. It is 2675 * sometimes okay to dial only the subscriber number when dialing in the same area. This 2676 * function will return IS_POSSIBLE_LOCAL_ONLY if the subscriber-number-only version is 2677 * passed in. On the other hand, because isValidNumber validates using information on both 2678 * starting digits (for fixed line numbers, that would most likely be area codes) and 2679 * length (obviously includes the length of area codes for fixed line numbers), it will 2680 * return false for the subscriber-number-only version. 2681 * </ol> 2682 * 2683 * @param number the number that needs to be checked 2684 * @param type the type we are interested in 2685 * @return a ValidationResult object which indicates whether the number is possible 2686 */ 2687 public ValidationResult isPossibleNumberForTypeWithReason( 2688 PhoneNumber number, PhoneNumberType type) { 2689 String nationalNumber = getNationalSignificantNumber(number); 2690 int countryCode = number.getCountryCode(); 2691 // Note: For regions that share a country calling code, like NANPA numbers, we just use the 2692 // rules from the default region (US in this case) since the getRegionCodeForNumber will not 2693 // work if the number is possible but not valid. There is in fact one country calling code (290) 2694 // where the possible number pattern differs between various regions (Saint Helena and Tristan 2695 // da Cuñha), but this is handled by putting all possible lengths for any country with this 2696 // country calling code in the metadata for the default region in this case. 2697 if (!hasValidCountryCallingCode(countryCode)) { 2698 return ValidationResult.INVALID_COUNTRY_CODE; 2699 } 2700 String regionCode = getRegionCodeForCountryCode(countryCode); 2701 // Metadata cannot be null because the country calling code is valid. 2702 PhoneMetadata metadata = getMetadataForRegionOrCallingCode(countryCode, regionCode); 2703 return testNumberLength(nationalNumber, metadata, type); 2704 } 2705 2706 /** 2707 * Check whether a phone number is a possible number given a number in the form of a string, and 2708 * the region where the number could be dialed from. It provides a more lenient check than 2709 * {@link #isValidNumber}. See {@link #isPossibleNumber(PhoneNumber)} for details. 2710 * 2711 * <p>This method first parses the number, then invokes {@link #isPossibleNumber(PhoneNumber)} 2712 * with the resultant PhoneNumber object. 2713 * 2714 * @param number the number that needs to be checked 2715 * @param regionDialingFrom the region that we are expecting the number to be dialed from. 2716 * Note this is different from the region where the number belongs. For example, the number 2717 * +1 650 253 0000 is a number that belongs to US. When written in this form, it can be 2718 * dialed from any region. When it is written as 00 1 650 253 0000, it can be dialed from any 2719 * region which uses an international dialling prefix of 00. When it is written as 2720 * 650 253 0000, it can only be dialed from within the US, and when written as 253 0000, it 2721 * can only be dialed from within a smaller area in the US (Mountain View, CA, to be more 2722 * specific). 2723 * @return true if the number is possible 2724 */ 2725 public boolean isPossibleNumber(CharSequence number, String regionDialingFrom) { 2726 try { 2727 return isPossibleNumber(parse(number, regionDialingFrom)); 2728 } catch (NumberParseException e) { 2729 return false; 2730 } 2731 } 2732 2733 /** 2734 * Attempts to extract a valid number from a phone number that is too long to be valid, and resets 2735 * the PhoneNumber object passed in to that valid version. If no valid number could be extracted, 2736 * the PhoneNumber object passed in will not be modified. 2737 * @param number a PhoneNumber object which contains a number that is too long to be valid 2738 * @return true if a valid phone number can be successfully extracted 2739 */ 2740 public boolean truncateTooLongNumber(PhoneNumber number) { 2741 if (isValidNumber(number)) { 2742 return true; 2743 } 2744 PhoneNumber numberCopy = new PhoneNumber(); 2745 numberCopy.mergeFrom(number); 2746 long nationalNumber = number.getNationalNumber(); 2747 do { 2748 nationalNumber /= 10; 2749 numberCopy.setNationalNumber(nationalNumber); 2750 if (isPossibleNumberWithReason(numberCopy) == ValidationResult.TOO_SHORT 2751 || nationalNumber == 0) { 2752 return false; 2753 } 2754 } while (!isValidNumber(numberCopy)); 2755 number.setNationalNumber(nationalNumber); 2756 return true; 2757 } 2758 2759 /** 2760 * Gets an {@link com.google.i18n.phonenumbers.AsYouTypeFormatter} for the specific region. 2761 * 2762 * @param regionCode the region where the phone number is being entered 2763 * @return an {@link com.google.i18n.phonenumbers.AsYouTypeFormatter} object, which can be used 2764 * to format phone numbers in the specific region "as you type" 2765 */ 2766 public AsYouTypeFormatter getAsYouTypeFormatter(String regionCode) { 2767 return new AsYouTypeFormatter(regionCode); 2768 } 2769 2770 // Extracts country calling code from fullNumber, returns it and places the remaining number in 2771 // nationalNumber. It assumes that the leading plus sign or IDD has already been removed. Returns 2772 // 0 if fullNumber doesn't start with a valid country calling code, and leaves nationalNumber 2773 // unmodified. 2774 int extractCountryCode(StringBuilder fullNumber, StringBuilder nationalNumber) { 2775 if ((fullNumber.length() == 0) || (fullNumber.charAt(0) == '0')) { 2776 // Country codes do not begin with a '0'. 2777 return 0; 2778 } 2779 int potentialCountryCode; 2780 int numberLength = fullNumber.length(); 2781 for (int i = 1; i <= MAX_LENGTH_COUNTRY_CODE && i <= numberLength; i++) { 2782 potentialCountryCode = Integer.parseInt(fullNumber.substring(0, i)); 2783 if (countryCallingCodeToRegionCodeMap.containsKey(potentialCountryCode)) { 2784 nationalNumber.append(fullNumber.substring(i)); 2785 return potentialCountryCode; 2786 } 2787 } 2788 return 0; 2789 } 2790 2791 /** 2792 * Tries to extract a country calling code from a number. This method will return zero if no 2793 * country calling code is considered to be present. Country calling codes are extracted in the 2794 * following ways: 2795 * <ul> 2796 * <li> by stripping the international dialing prefix of the region the person is dialing from, 2797 * if this is present in the number, and looking at the next digits 2798 * <li> by stripping the '+' sign if present and then looking at the next digits 2799 * <li> by comparing the start of the number and the country calling code of the default region. 2800 * If the number is not considered possible for the numbering plan of the default region 2801 * initially, but starts with the country calling code of this region, validation will be 2802 * reattempted after stripping this country calling code. If this number is considered a 2803 * possible number, then the first digits will be considered the country calling code and 2804 * removed as such. 2805 * </ul> 2806 * It will throw a NumberParseException if the number starts with a '+' but the country calling 2807 * code supplied after this does not match that of any known region. 2808 * 2809 * @param number non-normalized telephone number that we wish to extract a country calling 2810 * code from - may begin with '+' 2811 * @param defaultRegionMetadata metadata about the region this number may be from 2812 * @param nationalNumber a string buffer to store the national significant number in, in the case 2813 * that a country calling code was extracted. The number is appended to any existing contents. 2814 * If no country calling code was extracted, this will be left unchanged. 2815 * @param keepRawInput true if the country_code_source and preferred_carrier_code fields of 2816 * phoneNumber should be populated. 2817 * @param phoneNumber the PhoneNumber object where the country_code and country_code_source need 2818 * to be populated. Note the country_code is always populated, whereas country_code_source is 2819 * only populated when keepCountryCodeSource is true. 2820 * @return the country calling code extracted or 0 if none could be extracted 2821 */ 2822 // @VisibleForTesting 2823 int maybeExtractCountryCode(CharSequence number, PhoneMetadata defaultRegionMetadata, 2824 StringBuilder nationalNumber, boolean keepRawInput, 2825 PhoneNumber phoneNumber) 2826 throws NumberParseException { 2827 if (number.length() == 0) { 2828 return 0; 2829 } 2830 StringBuilder fullNumber = new StringBuilder(number); 2831 // Set the default prefix to be something that will never match. 2832 String possibleCountryIddPrefix = "NonMatch"; 2833 if (defaultRegionMetadata != null) { 2834 possibleCountryIddPrefix = defaultRegionMetadata.getInternationalPrefix(); 2835 } 2836 2837 CountryCodeSource countryCodeSource = 2838 maybeStripInternationalPrefixAndNormalize(fullNumber, possibleCountryIddPrefix); 2839 if (keepRawInput) { 2840 phoneNumber.setCountryCodeSource(countryCodeSource); 2841 } 2842 if (countryCodeSource != CountryCodeSource.FROM_DEFAULT_COUNTRY) { 2843 if (fullNumber.length() <= MIN_LENGTH_FOR_NSN) { 2844 throw new NumberParseException(NumberParseException.ErrorType.TOO_SHORT_AFTER_IDD, 2845 "Phone number had an IDD, but after this was not " 2846 + "long enough to be a viable phone number."); 2847 } 2848 int potentialCountryCode = extractCountryCode(fullNumber, nationalNumber); 2849 if (potentialCountryCode != 0) { 2850 phoneNumber.setCountryCode(potentialCountryCode); 2851 return potentialCountryCode; 2852 } 2853 2854 // If this fails, they must be using a strange country calling code that we don't recognize, 2855 // or that doesn't exist. 2856 throw new NumberParseException(NumberParseException.ErrorType.INVALID_COUNTRY_CODE, 2857 "Country calling code supplied was not recognised."); 2858 } else if (defaultRegionMetadata != null) { 2859 // Check to see if the number starts with the country calling code for the default region. If 2860 // so, we remove the country calling code, and do some checks on the validity of the number 2861 // before and after. 2862 int defaultCountryCode = defaultRegionMetadata.getCountryCode(); 2863 String defaultCountryCodeString = String.valueOf(defaultCountryCode); 2864 String normalizedNumber = fullNumber.toString(); 2865 if (normalizedNumber.startsWith(defaultCountryCodeString)) { 2866 StringBuilder potentialNationalNumber = 2867 new StringBuilder(normalizedNumber.substring(defaultCountryCodeString.length())); 2868 PhoneNumberDesc generalDesc = defaultRegionMetadata.getGeneralDesc(); 2869 maybeStripNationalPrefixAndCarrierCode( 2870 potentialNationalNumber, defaultRegionMetadata, null /* Don't need the carrier code */); 2871 // If the number was not valid before but is valid now, or if it was too long before, we 2872 // consider the number with the country calling code stripped to be a better result and 2873 // keep that instead. 2874 if ((!matcherApi.matchNationalNumber(fullNumber, generalDesc, false) 2875 && matcherApi.matchNationalNumber(potentialNationalNumber, generalDesc, false)) 2876 || testNumberLength(fullNumber, defaultRegionMetadata) == ValidationResult.TOO_LONG) { 2877 nationalNumber.append(potentialNationalNumber); 2878 if (keepRawInput) { 2879 phoneNumber.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN); 2880 } 2881 phoneNumber.setCountryCode(defaultCountryCode); 2882 return defaultCountryCode; 2883 } 2884 } 2885 } 2886 // No country calling code present. 2887 phoneNumber.setCountryCode(0); 2888 return 0; 2889 } 2890 2891 /** 2892 * Strips the IDD from the start of the number if present. Helper function used by 2893 * maybeStripInternationalPrefixAndNormalize. 2894 */ 2895 private boolean parsePrefixAsIdd(Pattern iddPattern, StringBuilder number) { 2896 Matcher m = iddPattern.matcher(number); 2897 if (m.lookingAt()) { 2898 int matchEnd = m.end(); 2899 // Only strip this if the first digit after the match is not a 0, since country calling codes 2900 // cannot begin with 0. 2901 Matcher digitMatcher = CAPTURING_DIGIT_PATTERN.matcher(number.substring(matchEnd)); 2902 if (digitMatcher.find()) { 2903 String normalizedGroup = normalizeDigitsOnly(digitMatcher.group(1)); 2904 if (normalizedGroup.equals("0")) { 2905 return false; 2906 } 2907 } 2908 number.delete(0, matchEnd); 2909 return true; 2910 } 2911 return false; 2912 } 2913 2914 /** 2915 * Strips any international prefix (such as +, 00, 011) present in the number provided, normalizes 2916 * the resulting number, and indicates if an international prefix was present. 2917 * 2918 * @param number the non-normalized telephone number that we wish to strip any international 2919 * dialing prefix from 2920 * @param possibleIddPrefix the international direct dialing prefix from the region we 2921 * think this number may be dialed in 2922 * @return the corresponding CountryCodeSource if an international dialing prefix could be 2923 * removed from the number, otherwise CountryCodeSource.FROM_DEFAULT_COUNTRY if the number did 2924 * not seem to be in international format 2925 */ 2926 // @VisibleForTesting 2927 CountryCodeSource maybeStripInternationalPrefixAndNormalize( 2928 StringBuilder number, 2929 String possibleIddPrefix) { 2930 if (number.length() == 0) { 2931 return CountryCodeSource.FROM_DEFAULT_COUNTRY; 2932 } 2933 // Check to see if the number begins with one or more plus signs. 2934 Matcher m = PLUS_CHARS_PATTERN.matcher(number); 2935 if (m.lookingAt()) { 2936 number.delete(0, m.end()); 2937 // Can now normalize the rest of the number since we've consumed the "+" sign at the start. 2938 normalize(number); 2939 return CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN; 2940 } 2941 // Attempt to parse the first digits as an international prefix. 2942 Pattern iddPattern = regexCache.getPatternForRegex(possibleIddPrefix); 2943 normalize(number); 2944 return parsePrefixAsIdd(iddPattern, number) 2945 ? CountryCodeSource.FROM_NUMBER_WITH_IDD 2946 : CountryCodeSource.FROM_DEFAULT_COUNTRY; 2947 } 2948 2949 /** 2950 * Strips any national prefix (such as 0, 1) present in the number provided. 2951 * 2952 * @param number the normalized telephone number that we wish to strip any national 2953 * dialing prefix from 2954 * @param metadata the metadata for the region that we think this number is from 2955 * @param carrierCode a place to insert the carrier code if one is extracted 2956 * @return true if a national prefix or carrier code (or both) could be extracted 2957 */ 2958 // @VisibleForTesting 2959 boolean maybeStripNationalPrefixAndCarrierCode( 2960 StringBuilder number, PhoneMetadata metadata, StringBuilder carrierCode) { 2961 int numberLength = number.length(); 2962 String possibleNationalPrefix = metadata.getNationalPrefixForParsing(); 2963 if (numberLength == 0 || possibleNationalPrefix.length() == 0) { 2964 // Early return for numbers of zero length. 2965 return false; 2966 } 2967 // Attempt to parse the first digits as a national prefix. 2968 Matcher prefixMatcher = regexCache.getPatternForRegex(possibleNationalPrefix).matcher(number); 2969 if (prefixMatcher.lookingAt()) { 2970 PhoneNumberDesc generalDesc = metadata.getGeneralDesc(); 2971 // Check if the original number is viable. 2972 boolean isViableOriginalNumber = matcherApi.matchNationalNumber(number, generalDesc, false); 2973 // prefixMatcher.group(numOfGroups) == null implies nothing was captured by the capturing 2974 // groups in possibleNationalPrefix; therefore, no transformation is necessary, and we just 2975 // remove the national prefix. 2976 int numOfGroups = prefixMatcher.groupCount(); 2977 String transformRule = metadata.getNationalPrefixTransformRule(); 2978 if (transformRule == null || transformRule.length() == 0 2979 || prefixMatcher.group(numOfGroups) == null) { 2980 // If the original number was viable, and the resultant number is not, we return. 2981 if (isViableOriginalNumber 2982 && !matcherApi.matchNationalNumber( 2983 number.substring(prefixMatcher.end()), generalDesc, false)) { 2984 return false; 2985 } 2986 if (carrierCode != null && numOfGroups > 0 && prefixMatcher.group(numOfGroups) != null) { 2987 carrierCode.append(prefixMatcher.group(1)); 2988 } 2989 number.delete(0, prefixMatcher.end()); 2990 return true; 2991 } else { 2992 // Check that the resultant number is still viable. If not, return. Check this by copying 2993 // the string buffer and making the transformation on the copy first. 2994 StringBuilder transformedNumber = new StringBuilder(number); 2995 transformedNumber.replace(0, numberLength, prefixMatcher.replaceFirst(transformRule)); 2996 if (isViableOriginalNumber 2997 && !matcherApi.matchNationalNumber(transformedNumber.toString(), generalDesc, false)) { 2998 return false; 2999 } 3000 if (carrierCode != null && numOfGroups > 1) { 3001 carrierCode.append(prefixMatcher.group(1)); 3002 } 3003 number.replace(0, number.length(), transformedNumber.toString()); 3004 return true; 3005 } 3006 } 3007 return false; 3008 } 3009 3010 /** 3011 * Strips any extension (as in, the part of the number dialled after the call is connected, 3012 * usually indicated with extn, ext, x or similar) from the end of the number, and returns it. 3013 * 3014 * @param number the non-normalized telephone number that we wish to strip the extension from 3015 * @return the phone extension 3016 */ 3017 // @VisibleForTesting 3018 String maybeStripExtension(StringBuilder number) { 3019 Matcher m = EXTN_PATTERN.matcher(number); 3020 // If we find a potential extension, and the number preceding this is a viable number, we assume 3021 // it is an extension. 3022 if (m.find() && isViablePhoneNumber(number.substring(0, m.start()))) { 3023 // The numbers are captured into groups in the regular expression. 3024 for (int i = 1, length = m.groupCount(); i <= length; i++) { 3025 if (m.group(i) != null) { 3026 // We go through the capturing groups until we find one that captured some digits. If none 3027 // did, then we will return the empty string. 3028 String extension = m.group(i); 3029 number.delete(m.start(), number.length()); 3030 return extension; 3031 } 3032 } 3033 } 3034 return ""; 3035 } 3036 3037 /** 3038 * Checks to see that the region code used is valid, or if it is not valid, that the number to 3039 * parse starts with a + symbol so that we can attempt to infer the region from the number. 3040 * Returns false if it cannot use the region provided and the region cannot be inferred. 3041 */ 3042 private boolean checkRegionForParsing(CharSequence numberToParse, String defaultRegion) { 3043 if (!isValidRegionCode(defaultRegion)) { 3044 // If the number is null or empty, we can't infer the region. 3045 if ((numberToParse == null) || (numberToParse.length() == 0) 3046 || !PLUS_CHARS_PATTERN.matcher(numberToParse).lookingAt()) { 3047 return false; 3048 } 3049 } 3050 return true; 3051 } 3052 3053 /** 3054 * Parses a string and returns it as a phone number in proto buffer format. The method is quite 3055 * lenient and looks for a number in the input text (raw input) and does not check whether the 3056 * string is definitely only a phone number. To do this, it ignores punctuation and white-space, 3057 * as well as any text before the number (e.g. a leading "Tel: ") and trims the non-number bits. 3058 * It will accept a number in any format (E164, national, international etc), assuming it can be 3059 * interpreted with the defaultRegion supplied. It also attempts to convert any alpha characters 3060 * into digits if it thinks this is a vanity number of the type "1800 MICROSOFT". 3061 * 3062 * <p> This method will throw a {@link com.google.i18n.phonenumbers.NumberParseException} if the 3063 * number is not considered to be a possible number. Note that validation of whether the number 3064 * is actually a valid number for a particular region is not performed. This can be done 3065 * separately with {@link #isValidNumber}. 3066 * 3067 * <p> Note this method canonicalizes the phone number such that different representations can be 3068 * easily compared, no matter what form it was originally entered in (e.g. national, 3069 * international). If you want to record context about the number being parsed, such as the raw 3070 * input that was entered, how the country code was derived etc. then call {@link 3071 * #parseAndKeepRawInput} instead. 3072 * 3073 * @param numberToParse number that we are attempting to parse. This can contain formatting such 3074 * as +, ( and -, as well as a phone number extension. It can also be provided in RFC3966 3075 * format. 3076 * @param defaultRegion region that we are expecting the number to be from. This is only used if 3077 * the number being parsed is not written in international format. The country_code for the 3078 * number in this case would be stored as that of the default region supplied. If the number 3079 * is guaranteed to start with a '+' followed by the country calling code, then RegionCode.ZZ 3080 * or null can be supplied. 3081 * @return a phone number proto buffer filled with the parsed number 3082 * @throws NumberParseException if the string is not considered to be a viable phone number (e.g. 3083 * too few or too many digits) or if no default region was supplied and the number is not in 3084 * international format (does not start with +) 3085 */ 3086 public PhoneNumber parse(CharSequence numberToParse, String defaultRegion) 3087 throws NumberParseException { 3088 PhoneNumber phoneNumber = new PhoneNumber(); 3089 parse(numberToParse, defaultRegion, phoneNumber); 3090 return phoneNumber; 3091 } 3092 3093 /** 3094 * Same as {@link #parse(CharSequence, String)}, but accepts mutable PhoneNumber as a 3095 * parameter to decrease object creation when invoked many times. 3096 */ 3097 public void parse(CharSequence numberToParse, String defaultRegion, PhoneNumber phoneNumber) 3098 throws NumberParseException { 3099 parseHelper(numberToParse, defaultRegion, false, true, phoneNumber); 3100 } 3101 3102 /** 3103 * Parses a string and returns it in proto buffer format. This method differs from {@link #parse} 3104 * in that it always populates the raw_input field of the protocol buffer with numberToParse as 3105 * well as the country_code_source field. 3106 * 3107 * @param numberToParse number that we are attempting to parse. This can contain formatting such 3108 * as +, ( and -, as well as a phone number extension. 3109 * @param defaultRegion region that we are expecting the number to be from. This is only used if 3110 * the number being parsed is not written in international format. The country calling code 3111 * for the number in this case would be stored as that of the default region supplied. 3112 * @return a phone number proto buffer filled with the parsed number 3113 * @throws NumberParseException if the string is not considered to be a viable phone number or if 3114 * no default region was supplied 3115 */ 3116 public PhoneNumber parseAndKeepRawInput(CharSequence numberToParse, String defaultRegion) 3117 throws NumberParseException { 3118 PhoneNumber phoneNumber = new PhoneNumber(); 3119 parseAndKeepRawInput(numberToParse, defaultRegion, phoneNumber); 3120 return phoneNumber; 3121 } 3122 3123 /** 3124 * Same as{@link #parseAndKeepRawInput(CharSequence, String)}, but accepts a mutable 3125 * PhoneNumber as a parameter to decrease object creation when invoked many times. 3126 */ 3127 public void parseAndKeepRawInput(CharSequence numberToParse, String defaultRegion, 3128 PhoneNumber phoneNumber) 3129 throws NumberParseException { 3130 parseHelper(numberToParse, defaultRegion, true, true, phoneNumber); 3131 } 3132 3133 /** 3134 * Returns an iterable over all {@link PhoneNumberMatch PhoneNumberMatches} in {@code text}. This 3135 * is a shortcut for {@link #findNumbers(CharSequence, String, Leniency, long) 3136 * getMatcher(text, defaultRegion, Leniency.VALID, Long.MAX_VALUE)}. 3137 * 3138 * @param text the text to search for phone numbers, null for no text 3139 * @param defaultRegion region that we are expecting the number to be from. This is only used if 3140 * the number being parsed is not written in international format. The country_code for the 3141 * number in this case would be stored as that of the default region supplied. May be null if 3142 * only international numbers are expected. 3143 */ 3144 public Iterable<PhoneNumberMatch> findNumbers(CharSequence text, String defaultRegion) { 3145 return findNumbers(text, defaultRegion, Leniency.VALID, Long.MAX_VALUE); 3146 } 3147 3148 /** 3149 * Returns an iterable over all {@link PhoneNumberMatch PhoneNumberMatches} in {@code text}. 3150 * 3151 * @param text the text to search for phone numbers, null for no text 3152 * @param defaultRegion region that we are expecting the number to be from. This is only used if 3153 * the number being parsed is not written in international format. The country_code for the 3154 * number in this case would be stored as that of the default region supplied. May be null if 3155 * only international numbers are expected. 3156 * @param leniency the leniency to use when evaluating candidate phone numbers 3157 * @param maxTries the maximum number of invalid numbers to try before giving up on the text. 3158 * This is to cover degenerate cases where the text has a lot of false positives in it. Must 3159 * be {@code >= 0}. 3160 */ 3161 public Iterable<PhoneNumberMatch> findNumbers( 3162 final CharSequence text, final String defaultRegion, final Leniency leniency, 3163 final long maxTries) { 3164 3165 return new Iterable<PhoneNumberMatch>() { 3166 @Override 3167 public Iterator<PhoneNumberMatch> iterator() { 3168 return new PhoneNumberMatcher( 3169 PhoneNumberUtil.this, text, defaultRegion, leniency, maxTries); 3170 } 3171 }; 3172 } 3173 3174 /** 3175 * A helper function to set the values related to leading zeros in a PhoneNumber. 3176 */ 3177 static void setItalianLeadingZerosForPhoneNumber(CharSequence nationalNumber, 3178 PhoneNumber phoneNumber) { 3179 if (nationalNumber.length() > 1 && nationalNumber.charAt(0) == '0') { 3180 phoneNumber.setItalianLeadingZero(true); 3181 int numberOfLeadingZeros = 1; 3182 // Note that if the national number is all "0"s, the last "0" is not counted as a leading 3183 // zero. 3184 while (numberOfLeadingZeros < nationalNumber.length() - 1 3185 && nationalNumber.charAt(numberOfLeadingZeros) == '0') { 3186 numberOfLeadingZeros++; 3187 } 3188 if (numberOfLeadingZeros != 1) { 3189 phoneNumber.setNumberOfLeadingZeros(numberOfLeadingZeros); 3190 } 3191 } 3192 } 3193 3194 /** 3195 * Parses a string and fills up the phoneNumber. This method is the same as the public 3196 * parse() method, with the exception that it allows the default region to be null, for use by 3197 * isNumberMatch(). checkRegion should be set to false if it is permitted for the default region 3198 * to be null or unknown ("ZZ"). 3199 * 3200 * Note if any new field is added to this method that should always be filled in, even when 3201 * keepRawInput is false, it should also be handled in the copyCoreFieldsOnly() method. 3202 */ 3203 private void parseHelper(CharSequence numberToParse, String defaultRegion, 3204 boolean keepRawInput, boolean checkRegion, PhoneNumber phoneNumber) 3205 throws NumberParseException { 3206 if (numberToParse == null) { 3207 throw new NumberParseException(NumberParseException.ErrorType.NOT_A_NUMBER, 3208 "The phone number supplied was null."); 3209 } else if (numberToParse.length() > MAX_INPUT_STRING_LENGTH) { 3210 throw new NumberParseException(NumberParseException.ErrorType.TOO_LONG, 3211 "The string supplied was too long to parse."); 3212 } 3213 3214 StringBuilder nationalNumber = new StringBuilder(); 3215 String numberBeingParsed = numberToParse.toString(); 3216 buildNationalNumberForParsing(numberBeingParsed, nationalNumber); 3217 3218 if (!isViablePhoneNumber(nationalNumber)) { 3219 throw new NumberParseException(NumberParseException.ErrorType.NOT_A_NUMBER, 3220 "The string supplied did not seem to be a phone number."); 3221 } 3222 3223 // Check the region supplied is valid, or that the extracted number starts with some sort of + 3224 // sign so the number's region can be determined. 3225 if (checkRegion && !checkRegionForParsing(nationalNumber, defaultRegion)) { 3226 throw new NumberParseException(NumberParseException.ErrorType.INVALID_COUNTRY_CODE, 3227 "Missing or invalid default region."); 3228 } 3229 3230 if (keepRawInput) { 3231 phoneNumber.setRawInput(numberBeingParsed); 3232 } 3233 // Attempt to parse extension first, since it doesn't require region-specific data and we want 3234 // to have the non-normalised number here. 3235 String extension = maybeStripExtension(nationalNumber); 3236 if (extension.length() > 0) { 3237 phoneNumber.setExtension(extension); 3238 } 3239 3240 PhoneMetadata regionMetadata = getMetadataForRegion(defaultRegion); 3241 // Check to see if the number is given in international format so we know whether this number is 3242 // from the default region or not. 3243 StringBuilder normalizedNationalNumber = new StringBuilder(); 3244 int countryCode = 0; 3245 try { 3246 // TODO: This method should really just take in the string buffer that has already 3247 // been created, and just remove the prefix, rather than taking in a string and then 3248 // outputting a string buffer. 3249 countryCode = maybeExtractCountryCode(nationalNumber, regionMetadata, 3250 normalizedNationalNumber, keepRawInput, phoneNumber); 3251 } catch (NumberParseException e) { 3252 Matcher matcher = PLUS_CHARS_PATTERN.matcher(nationalNumber); 3253 if (e.getErrorType() == NumberParseException.ErrorType.INVALID_COUNTRY_CODE 3254 && matcher.lookingAt()) { 3255 // Strip the plus-char, and try again. 3256 countryCode = maybeExtractCountryCode(nationalNumber.substring(matcher.end()), 3257 regionMetadata, normalizedNationalNumber, 3258 keepRawInput, phoneNumber); 3259 if (countryCode == 0) { 3260 throw new NumberParseException(NumberParseException.ErrorType.INVALID_COUNTRY_CODE, 3261 "Could not interpret numbers after plus-sign."); 3262 } 3263 } else { 3264 throw new NumberParseException(e.getErrorType(), e.getMessage()); 3265 } 3266 } 3267 if (countryCode != 0) { 3268 String phoneNumberRegion = getRegionCodeForCountryCode(countryCode); 3269 if (!phoneNumberRegion.equals(defaultRegion)) { 3270 // Metadata cannot be null because the country calling code is valid. 3271 regionMetadata = getMetadataForRegionOrCallingCode(countryCode, phoneNumberRegion); 3272 } 3273 } else { 3274 // If no extracted country calling code, use the region supplied instead. The national number 3275 // is just the normalized version of the number we were given to parse. 3276 normalizedNationalNumber.append(normalize(nationalNumber)); 3277 if (defaultRegion != null) { 3278 countryCode = regionMetadata.getCountryCode(); 3279 phoneNumber.setCountryCode(countryCode); 3280 } else if (keepRawInput) { 3281 phoneNumber.clearCountryCodeSource(); 3282 } 3283 } 3284 if (normalizedNationalNumber.length() < MIN_LENGTH_FOR_NSN) { 3285 throw new NumberParseException(NumberParseException.ErrorType.TOO_SHORT_NSN, 3286 "The string supplied is too short to be a phone number."); 3287 } 3288 if (regionMetadata != null) { 3289 StringBuilder carrierCode = new StringBuilder(); 3290 StringBuilder potentialNationalNumber = new StringBuilder(normalizedNationalNumber); 3291 maybeStripNationalPrefixAndCarrierCode(potentialNationalNumber, regionMetadata, carrierCode); 3292 // We require that the NSN remaining after stripping the national prefix and carrier code be 3293 // long enough to be a possible length for the region. Otherwise, we don't do the stripping, 3294 // since the original number could be a valid short number. 3295 ValidationResult validationResult = testNumberLength(potentialNationalNumber, regionMetadata); 3296 if (validationResult != ValidationResult.TOO_SHORT 3297 && validationResult != ValidationResult.IS_POSSIBLE_LOCAL_ONLY 3298 && validationResult != ValidationResult.INVALID_LENGTH) { 3299 normalizedNationalNumber = potentialNationalNumber; 3300 if (keepRawInput && carrierCode.length() > 0) { 3301 phoneNumber.setPreferredDomesticCarrierCode(carrierCode.toString()); 3302 } 3303 } 3304 } 3305 int lengthOfNationalNumber = normalizedNationalNumber.length(); 3306 if (lengthOfNationalNumber < MIN_LENGTH_FOR_NSN) { 3307 throw new NumberParseException(NumberParseException.ErrorType.TOO_SHORT_NSN, 3308 "The string supplied is too short to be a phone number."); 3309 } 3310 if (lengthOfNationalNumber > MAX_LENGTH_FOR_NSN) { 3311 throw new NumberParseException(NumberParseException.ErrorType.TOO_LONG, 3312 "The string supplied is too long to be a phone number."); 3313 } 3314 setItalianLeadingZerosForPhoneNumber(normalizedNationalNumber, phoneNumber); 3315 phoneNumber.setNationalNumber(Long.parseLong(normalizedNationalNumber.toString())); 3316 } 3317 3318 /** 3319 * Converts numberToParse to a form that we can parse and write it to nationalNumber if it is 3320 * written in RFC3966; otherwise extract a possible number out of it and write to nationalNumber. 3321 */ 3322 private void buildNationalNumberForParsing(String numberToParse, StringBuilder nationalNumber) { 3323 int indexOfPhoneContext = numberToParse.indexOf(RFC3966_PHONE_CONTEXT); 3324 if (indexOfPhoneContext >= 0) { 3325 int phoneContextStart = indexOfPhoneContext + RFC3966_PHONE_CONTEXT.length(); 3326 // If the phone context contains a phone number prefix, we need to capture it, whereas domains 3327 // will be ignored. 3328 if (phoneContextStart < (numberToParse.length() - 1) 3329 && numberToParse.charAt(phoneContextStart) == PLUS_SIGN) { 3330 // Additional parameters might follow the phone context. If so, we will remove them here 3331 // because the parameters after phone context are not important for parsing the 3332 // phone number. 3333 int phoneContextEnd = numberToParse.indexOf(';', phoneContextStart); 3334 if (phoneContextEnd > 0) { 3335 nationalNumber.append(numberToParse.substring(phoneContextStart, phoneContextEnd)); 3336 } else { 3337 nationalNumber.append(numberToParse.substring(phoneContextStart)); 3338 } 3339 } 3340 3341 // Now append everything between the "tel:" prefix and the phone-context. This should include 3342 // the national number, an optional extension or isdn-subaddress component. Note we also 3343 // handle the case when "tel:" is missing, as we have seen in some of the phone number inputs. 3344 // In that case, we append everything from the beginning. 3345 int indexOfRfc3966Prefix = numberToParse.indexOf(RFC3966_PREFIX); 3346 int indexOfNationalNumber = (indexOfRfc3966Prefix >= 0) 3347 ? indexOfRfc3966Prefix + RFC3966_PREFIX.length() : 0; 3348 nationalNumber.append(numberToParse.substring(indexOfNationalNumber, indexOfPhoneContext)); 3349 } else { 3350 // Extract a possible number from the string passed in (this strips leading characters that 3351 // could not be the start of a phone number.) 3352 nationalNumber.append(extractPossibleNumber(numberToParse)); 3353 } 3354 3355 // Delete the isdn-subaddress and everything after it if it is present. Note extension won't 3356 // appear at the same time with isdn-subaddress according to paragraph 5.3 of the RFC3966 spec, 3357 int indexOfIsdn = nationalNumber.indexOf(RFC3966_ISDN_SUBADDRESS); 3358 if (indexOfIsdn > 0) { 3359 nationalNumber.delete(indexOfIsdn, nationalNumber.length()); 3360 } 3361 // If both phone context and isdn-subaddress are absent but other parameters are present, the 3362 // parameters are left in nationalNumber. This is because we are concerned about deleting 3363 // content from a potential number string when there is no strong evidence that the number is 3364 // actually written in RFC3966. 3365 } 3366 3367 /** 3368 * Returns a new phone number containing only the fields needed to uniquely identify a phone 3369 * number, rather than any fields that capture the context in which the phone number was created. 3370 * These fields correspond to those set in parse() rather than parseAndKeepRawInput(). 3371 */ 3372 private static PhoneNumber copyCoreFieldsOnly(PhoneNumber phoneNumberIn) { 3373 PhoneNumber phoneNumber = new PhoneNumber(); 3374 phoneNumber.setCountryCode(phoneNumberIn.getCountryCode()); 3375 phoneNumber.setNationalNumber(phoneNumberIn.getNationalNumber()); 3376 if (phoneNumberIn.getExtension().length() > 0) { 3377 phoneNumber.setExtension(phoneNumberIn.getExtension()); 3378 } 3379 if (phoneNumberIn.isItalianLeadingZero()) { 3380 phoneNumber.setItalianLeadingZero(true); 3381 // This field is only relevant if there are leading zeros at all. 3382 phoneNumber.setNumberOfLeadingZeros(phoneNumberIn.getNumberOfLeadingZeros()); 3383 } 3384 return phoneNumber; 3385 } 3386 3387 /** 3388 * Takes two phone numbers and compares them for equality. 3389 * 3390 * <p>Returns EXACT_MATCH if the country_code, NSN, presence of a leading zero for Italian numbers 3391 * and any extension present are the same. 3392 * Returns NSN_MATCH if either or both has no region specified, and the NSNs and extensions are 3393 * the same. 3394 * Returns SHORT_NSN_MATCH if either or both has no region specified, or the region specified is 3395 * the same, and one NSN could be a shorter version of the other number. This includes the case 3396 * where one has an extension specified, and the other does not. 3397 * Returns NO_MATCH otherwise. 3398 * For example, the numbers +1 345 657 1234 and 657 1234 are a SHORT_NSN_MATCH. 3399 * The numbers +1 345 657 1234 and 345 657 are a NO_MATCH. 3400 * 3401 * @param firstNumberIn first number to compare 3402 * @param secondNumberIn second number to compare 3403 * 3404 * @return NO_MATCH, SHORT_NSN_MATCH, NSN_MATCH or EXACT_MATCH depending on the level of equality 3405 * of the two numbers, described in the method definition. 3406 */ 3407 public MatchType isNumberMatch(PhoneNumber firstNumberIn, PhoneNumber secondNumberIn) { 3408 // We only care about the fields that uniquely define a number, so we copy these across 3409 // explicitly. 3410 PhoneNumber firstNumber = copyCoreFieldsOnly(firstNumberIn); 3411 PhoneNumber secondNumber = copyCoreFieldsOnly(secondNumberIn); 3412 // Early exit if both had extensions and these are different. 3413 if (firstNumber.hasExtension() && secondNumber.hasExtension() 3414 && !firstNumber.getExtension().equals(secondNumber.getExtension())) { 3415 return MatchType.NO_MATCH; 3416 } 3417 int firstNumberCountryCode = firstNumber.getCountryCode(); 3418 int secondNumberCountryCode = secondNumber.getCountryCode(); 3419 // Both had country_code specified. 3420 if (firstNumberCountryCode != 0 && secondNumberCountryCode != 0) { 3421 if (firstNumber.exactlySameAs(secondNumber)) { 3422 return MatchType.EXACT_MATCH; 3423 } else if (firstNumberCountryCode == secondNumberCountryCode 3424 && isNationalNumberSuffixOfTheOther(firstNumber, secondNumber)) { 3425 // A SHORT_NSN_MATCH occurs if there is a difference because of the presence or absence of 3426 // an 'Italian leading zero', the presence or absence of an extension, or one NSN being a 3427 // shorter variant of the other. 3428 return MatchType.SHORT_NSN_MATCH; 3429 } 3430 // This is not a match. 3431 return MatchType.NO_MATCH; 3432 } 3433 // Checks cases where one or both country_code fields were not specified. To make equality 3434 // checks easier, we first set the country_code fields to be equal. 3435 firstNumber.setCountryCode(secondNumberCountryCode); 3436 // If all else was the same, then this is an NSN_MATCH. 3437 if (firstNumber.exactlySameAs(secondNumber)) { 3438 return MatchType.NSN_MATCH; 3439 } 3440 if (isNationalNumberSuffixOfTheOther(firstNumber, secondNumber)) { 3441 return MatchType.SHORT_NSN_MATCH; 3442 } 3443 return MatchType.NO_MATCH; 3444 } 3445 3446 // Returns true when one national number is the suffix of the other or both are the same. 3447 private boolean isNationalNumberSuffixOfTheOther(PhoneNumber firstNumber, 3448 PhoneNumber secondNumber) { 3449 String firstNumberNationalNumber = String.valueOf(firstNumber.getNationalNumber()); 3450 String secondNumberNationalNumber = String.valueOf(secondNumber.getNationalNumber()); 3451 // Note that endsWith returns true if the numbers are equal. 3452 return firstNumberNationalNumber.endsWith(secondNumberNationalNumber) 3453 || secondNumberNationalNumber.endsWith(firstNumberNationalNumber); 3454 } 3455 3456 /** 3457 * Takes two phone numbers as strings and compares them for equality. This is a convenience 3458 * wrapper for {@link #isNumberMatch(PhoneNumber, PhoneNumber)}. No default region is known. 3459 * 3460 * @param firstNumber first number to compare. Can contain formatting, and can have country 3461 * calling code specified with + at the start. 3462 * @param secondNumber second number to compare. Can contain formatting, and can have country 3463 * calling code specified with + at the start. 3464 * @return NOT_A_NUMBER, NO_MATCH, SHORT_NSN_MATCH, NSN_MATCH, EXACT_MATCH. See 3465 * {@link #isNumberMatch(PhoneNumber, PhoneNumber)} for more details. 3466 */ 3467 public MatchType isNumberMatch(CharSequence firstNumber, CharSequence secondNumber) { 3468 try { 3469 PhoneNumber firstNumberAsProto = parse(firstNumber, UNKNOWN_REGION); 3470 return isNumberMatch(firstNumberAsProto, secondNumber); 3471 } catch (NumberParseException e) { 3472 if (e.getErrorType() == NumberParseException.ErrorType.INVALID_COUNTRY_CODE) { 3473 try { 3474 PhoneNumber secondNumberAsProto = parse(secondNumber, UNKNOWN_REGION); 3475 return isNumberMatch(secondNumberAsProto, firstNumber); 3476 } catch (NumberParseException e2) { 3477 if (e2.getErrorType() == NumberParseException.ErrorType.INVALID_COUNTRY_CODE) { 3478 try { 3479 PhoneNumber firstNumberProto = new PhoneNumber(); 3480 PhoneNumber secondNumberProto = new PhoneNumber(); 3481 parseHelper(firstNumber, null, false, false, firstNumberProto); 3482 parseHelper(secondNumber, null, false, false, secondNumberProto); 3483 return isNumberMatch(firstNumberProto, secondNumberProto); 3484 } catch (NumberParseException e3) { 3485 // Fall through and return MatchType.NOT_A_NUMBER. 3486 } 3487 } 3488 } 3489 } 3490 } 3491 // One or more of the phone numbers we are trying to match is not a viable phone number. 3492 return MatchType.NOT_A_NUMBER; 3493 } 3494 3495 /** 3496 * Takes two phone numbers and compares them for equality. This is a convenience wrapper for 3497 * {@link #isNumberMatch(PhoneNumber, PhoneNumber)}. No default region is known. 3498 * 3499 * @param firstNumber first number to compare in proto buffer format 3500 * @param secondNumber second number to compare. Can contain formatting, and can have country 3501 * calling code specified with + at the start. 3502 * @return NOT_A_NUMBER, NO_MATCH, SHORT_NSN_MATCH, NSN_MATCH, EXACT_MATCH. See 3503 * {@link #isNumberMatch(PhoneNumber, PhoneNumber)} for more details. 3504 */ 3505 public MatchType isNumberMatch(PhoneNumber firstNumber, CharSequence secondNumber) { 3506 // First see if the second number has an implicit country calling code, by attempting to parse 3507 // it. 3508 try { 3509 PhoneNumber secondNumberAsProto = parse(secondNumber, UNKNOWN_REGION); 3510 return isNumberMatch(firstNumber, secondNumberAsProto); 3511 } catch (NumberParseException e) { 3512 if (e.getErrorType() == NumberParseException.ErrorType.INVALID_COUNTRY_CODE) { 3513 // The second number has no country calling code. EXACT_MATCH is no longer possible. 3514 // We parse it as if the region was the same as that for the first number, and if 3515 // EXACT_MATCH is returned, we replace this with NSN_MATCH. 3516 String firstNumberRegion = getRegionCodeForCountryCode(firstNumber.getCountryCode()); 3517 try { 3518 if (!firstNumberRegion.equals(UNKNOWN_REGION)) { 3519 PhoneNumber secondNumberWithFirstNumberRegion = parse(secondNumber, firstNumberRegion); 3520 MatchType match = isNumberMatch(firstNumber, secondNumberWithFirstNumberRegion); 3521 if (match == MatchType.EXACT_MATCH) { 3522 return MatchType.NSN_MATCH; 3523 } 3524 return match; 3525 } else { 3526 // If the first number didn't have a valid country calling code, then we parse the 3527 // second number without one as well. 3528 PhoneNumber secondNumberProto = new PhoneNumber(); 3529 parseHelper(secondNumber, null, false, false, secondNumberProto); 3530 return isNumberMatch(firstNumber, secondNumberProto); 3531 } 3532 } catch (NumberParseException e2) { 3533 // Fall-through to return NOT_A_NUMBER. 3534 } 3535 } 3536 } 3537 // One or more of the phone numbers we are trying to match is not a viable phone number. 3538 return MatchType.NOT_A_NUMBER; 3539 } 3540 3541 /** 3542 * Returns true if the number can be dialled from outside the region, or unknown. If the number 3543 * can only be dialled from within the region, returns false. Does not check the number is a valid 3544 * number. Note that, at the moment, this method does not handle short numbers (which are 3545 * currently all presumed to not be diallable from outside their country). 3546 * 3547 * @param number the phone-number for which we want to know whether it is diallable from 3548 * outside the region 3549 */ 3550 public boolean canBeInternationallyDialled(PhoneNumber number) { 3551 PhoneMetadata metadata = getMetadataForRegion(getRegionCodeForNumber(number)); 3552 if (metadata == null) { 3553 // Note numbers belonging to non-geographical entities (e.g. +800 numbers) are always 3554 // internationally diallable, and will be caught here. 3555 return true; 3556 } 3557 String nationalSignificantNumber = getNationalSignificantNumber(number); 3558 return !isNumberMatchingDesc(nationalSignificantNumber, metadata.getNoInternationalDialling()); 3559 } 3560 3561 /** 3562 * Returns true if the supplied region supports mobile number portability. Returns false for 3563 * invalid, unknown or regions that don't support mobile number portability. 3564 * 3565 * @param regionCode the region for which we want to know whether it supports mobile number 3566 * portability or not 3567 */ 3568 public boolean isMobileNumberPortableRegion(String regionCode) { 3569 PhoneMetadata metadata = getMetadataForRegion(regionCode); 3570 if (metadata == null) { 3571 logger.log(Level.WARNING, "Invalid or unknown region code provided: " + regionCode); 3572 return false; 3573 } 3574 return metadata.getMobileNumberPortableRegion(); 3575 } 3576 } 3577