Browse Source

Code clean-up Java (#1354)

- LOGGER -> logger
- Small comment fixes
- Style-guide-recommended formatting changes
- Removal of duplicate, unneeded method in PhoneNumberToTimeZonesMapper.java for canBeGeocoded, using phoneNumberUtil instead.
pull/1361/head
lararennie 9 years ago
committed by GitHub
parent
commit
4fa93bb92b
26 changed files with 351 additions and 345 deletions
  1. +3
    -3
      java/carrier/src/com/google/i18n/phonenumbers/PhoneNumberToCarrierMapper.java
  2. +5
    -17
      java/geocoder/src/com/google/i18n/phonenumbers/PhoneNumberToTimeZonesMapper.java
  3. +2
    -2
      java/geocoder/src/com/google/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder.java
  4. +2
    -2
      java/internal/prefixmapper/src/com/google/i18n/phonenumbers/prefixmapper/MappingFileProvider.java
  5. +2
    -2
      java/internal/prefixmapper/src/com/google/i18n/phonenumbers/prefixmapper/PhonePrefixMap.java
  6. +8
    -8
      java/internal/prefixmapper/src/com/google/i18n/phonenumbers/prefixmapper/PrefixFileReader.java
  7. +2
    -2
      java/internal/prefixmapper/src/com/google/i18n/phonenumbers/prefixmapper/PrefixTimeZonesMap.java
  8. +2
    -2
      java/internal/prefixmapper/test/com/google/i18n/phonenumbers/prefixmapper/MappingFileProviderTest.java
  9. +21
    -18
      java/libphonenumber/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java
  10. +1
    -0
      java/libphonenumber/src/com/google/i18n/phonenumbers/MetadataSource.java
  11. +23
    -9
      java/libphonenumber/src/com/google/i18n/phonenumbers/NumberParseException.java
  12. +2
    -2
      java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberMatch.java
  13. +34
    -34
      java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberMatcher.java
  14. +163
    -168
      java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java
  15. +2
    -2
      java/libphonenumber/src/com/google/i18n/phonenumbers/RegexCache.java
  16. +1
    -1
      java/libphonenumber/src/com/google/i18n/phonenumbers/ShortNumberInfo.java
  17. +19
    -19
      java/libphonenumber/test/com/google/i18n/phonenumbers/ExampleNumbersTest.java
  18. +4
    -4
      java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberMatcherTest.java
  19. +8
    -1
      java/pending_code_changes.txt
  20. +4
    -5
      tools/java/common/src/com/google/i18n/phonenumbers/BuildMetadataFromXml.java
  21. +16
    -16
      tools/java/java-build/src/com/google/i18n/phonenumbers/BuildMetadataJsonFromXml.java
  22. +2
    -2
      tools/java/java-build/src/com/google/i18n/phonenumbers/buildtools/AbstractPhonePrefixDataIOHandler.java
  23. +9
    -9
      tools/java/java-build/src/com/google/i18n/phonenumbers/buildtools/GeneratePhonePrefixData.java
  24. +5
    -4
      tools/java/java-build/src/com/google/i18n/phonenumbers/buildtools/GeneratePhonePrefixDataEntryPoint.java
  25. +6
    -8
      tools/java/java-build/src/com/google/i18n/phonenumbers/buildtools/GenerateTimeZonesMapData.java
  26. +5
    -5
      tools/java/java-build/src/com/google/i18n/phonenumbers/buildtools/GenerateTimeZonesMapDataEntryPoint.java

+ 3
- 3
java/carrier/src/com/google/i18n/phonenumbers/PhoneNumberToCarrierMapper.java View File

@ -117,8 +117,8 @@ public class PhoneNumberToCarrierMapper {
* Checks if the supplied number type supports carrier lookup. * Checks if the supplied number type supports carrier lookup.
*/ */
private boolean isMobile(PhoneNumberType numberType) { private boolean isMobile(PhoneNumberType numberType) {
return (numberType == PhoneNumberType.MOBILE ||
numberType == PhoneNumberType.FIXED_LINE_OR_MOBILE ||
numberType == PhoneNumberType.PAGER);
return (numberType == PhoneNumberType.MOBILE
|| numberType == PhoneNumberType.FIXED_LINE_OR_MOBILE
|| numberType == PhoneNumberType.PAGER);
} }
} }

+ 5
- 17
java/geocoder/src/com/google/i18n/phonenumbers/PhoneNumberToTimeZonesMapper.java View File

@ -45,7 +45,7 @@ public class PhoneNumberToTimeZonesMapper {
UNKNOWN_TIME_ZONE_LIST.add(UNKNOWN_TIMEZONE); UNKNOWN_TIME_ZONE_LIST.add(UNKNOWN_TIMEZONE);
} }
private static final Logger LOGGER =
private static final Logger logger =
Logger.getLogger(PhoneNumberToTimeZonesMapper.class.getName()); Logger.getLogger(PhoneNumberToTimeZonesMapper.class.getName());
private PrefixTimeZonesMap prefixTimeZonesMap = null; private PrefixTimeZonesMap prefixTimeZonesMap = null;
@ -68,7 +68,7 @@ public class PhoneNumberToTimeZonesMapper {
in = new ObjectInputStream(source); in = new ObjectInputStream(source);
map.readExternal(in); map.readExternal(in);
} catch (IOException e) { } catch (IOException e) {
LOGGER.log(Level.WARNING, e.toString());
logger.log(Level.WARNING, e.toString());
} finally { } finally {
close(in); close(in);
} }
@ -80,7 +80,7 @@ public class PhoneNumberToTimeZonesMapper {
try { try {
in.close(); in.close();
} catch (IOException e) { } catch (IOException e) {
LOGGER.log(Level.WARNING, e.toString());
logger.log(Level.WARNING, e.toString());
} }
} }
} }
@ -137,25 +137,13 @@ public class PhoneNumberToTimeZonesMapper {
PhoneNumberType numberType = PhoneNumberUtil.getInstance().getNumberType(number); PhoneNumberType numberType = PhoneNumberUtil.getInstance().getNumberType(number);
if (numberType == PhoneNumberType.UNKNOWN) { if (numberType == PhoneNumberType.UNKNOWN) {
return UNKNOWN_TIME_ZONE_LIST; return UNKNOWN_TIME_ZONE_LIST;
} else if (!canBeGeocoded(numberType)) {
} else if (!PhoneNumberUtil.getInstance().isNumberGeographical(
numberType, number.getCountryCode())) {
return getCountryLevelTimeZonesforNumber(number); return getCountryLevelTimeZonesforNumber(number);
} }
return getTimeZonesForGeographicalNumber(number); return getTimeZonesForGeographicalNumber(number);
} }
/**
* A similar method is implemented as PhoneNumberUtil.isNumberGeographical, which performs a
* stricter check, as it determines if a number has a geographical association. Also, if new
* phone number types were added, we should check if this other method should be updated too.
* TODO: Remove duplication by completing the logic in the method in PhoneNumberUtil.
* For more information, see the comments in that method.
*/
private boolean canBeGeocoded(PhoneNumberType numberType) {
return (numberType == PhoneNumberType.FIXED_LINE ||
numberType == PhoneNumberType.MOBILE ||
numberType == PhoneNumberType.FIXED_LINE_OR_MOBILE);
}
/** /**
* Returns a String with the ICU unknown time zone. * Returns a String with the ICU unknown time zone.
*/ */


+ 2
- 2
java/geocoder/src/com/google/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder.java View File

@ -88,8 +88,8 @@ public class PhoneNumberOfflineGeocoder {
* Returns the customary display name in the given language for the given region. * Returns the customary display name in the given language for the given region.
*/ */
private String getRegionDisplayName(String regionCode, Locale language) { private String getRegionDisplayName(String regionCode, Locale language) {
return (regionCode == null || regionCode.equals("ZZ") ||
regionCode.equals(PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY))
return (regionCode == null || regionCode.equals("ZZ")
|| regionCode.equals(PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY))
? "" : new Locale("", regionCode).getDisplayCountry(language); ? "" : new Locale("", regionCode).getDisplayCountry(language);
} }


+ 2
- 2
java/internal/prefixmapper/src/com/google/i18n/phonenumbers/prefixmapper/MappingFileProvider.java View File

@ -210,8 +210,8 @@ public class MappingFileProvider implements Externalizable {
} }
private boolean onlyOneOfScriptOrRegionIsEmpty(String script, String region) { private boolean onlyOneOfScriptOrRegionIsEmpty(String script, String region) {
return (script.length() == 0 && region.length() > 0) ||
(region.length() == 0 && script.length() > 0);
return (script.length() == 0 && region.length() > 0)
|| (region.length() == 0 && script.length() > 0);
} }
private StringBuilder constructFullLocale(String language, String script, String region) { private StringBuilder constructFullLocale(String language, String script, String region) {


+ 2
- 2
java/internal/prefixmapper/src/com/google/i18n/phonenumbers/prefixmapper/PhonePrefixMap.java View File

@ -37,7 +37,7 @@ import java.util.logging.Logger;
*/ */
public class PhonePrefixMap implements Externalizable { public class PhonePrefixMap implements Externalizable {
private final PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); private final PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
private static final Logger LOGGER = Logger.getLogger(PhonePrefixMap.class.getName());
private static final Logger logger = Logger.getLogger(PhonePrefixMap.class.getName());
private PhonePrefixMapStorageStrategy phonePrefixMapStorage; private PhonePrefixMapStorageStrategy phonePrefixMapStorage;
@ -96,7 +96,7 @@ public class PhonePrefixMap implements Externalizable {
return sizeOfFlyweightMapStorage < sizeOfDefaultMapStorage return sizeOfFlyweightMapStorage < sizeOfDefaultMapStorage
? flyweightMapStorage : defaultMapStorage; ? flyweightMapStorage : defaultMapStorage;
} catch (IOException e) { } catch (IOException e) {
LOGGER.severe(e.getMessage());
logger.severe(e.getMessage());
return createFlyweightMapStorage(); return createFlyweightMapStorage();
} }
} }


+ 8
- 8
java/internal/prefixmapper/src/com/google/i18n/phonenumbers/prefixmapper/PrefixFileReader.java View File

@ -32,7 +32,7 @@ import java.util.logging.Logger;
* @author Shaopeng Jia * @author Shaopeng Jia
*/ */
public class PrefixFileReader { public class PrefixFileReader {
private static final Logger LOGGER = Logger.getLogger(PrefixFileReader.class.getName());
private static final Logger logger = Logger.getLogger(PrefixFileReader.class.getName());
private final String phonePrefixDataDirectory; private final String phonePrefixDataDirectory;
// The mappingFileProvider knows for which combination of countryCallingCode and language a phone // The mappingFileProvider knows for which combination of countryCallingCode and language a phone
@ -56,7 +56,7 @@ public class PrefixFileReader {
in = new ObjectInputStream(source); in = new ObjectInputStream(source);
mappingFileProvider.readExternal(in); mappingFileProvider.readExternal(in);
} catch (IOException e) { } catch (IOException e) {
LOGGER.log(Level.WARNING, e.toString());
logger.log(Level.WARNING, e.toString());
} finally { } finally {
close(in); close(in);
} }
@ -84,7 +84,7 @@ public class PrefixFileReader {
map.readExternal(in); map.readExternal(in);
availablePhonePrefixMaps.put(fileName, map); availablePhonePrefixMaps.put(fileName, map);
} catch (IOException e) { } catch (IOException e) {
LOGGER.log(Level.WARNING, e.toString());
logger.log(Level.WARNING, e.toString());
} finally { } finally {
close(in); close(in);
} }
@ -95,7 +95,7 @@ public class PrefixFileReader {
try { try {
in.close(); in.close();
} catch (IOException e) { } catch (IOException e) {
LOGGER.log(Level.WARNING, e.toString());
logger.log(Level.WARNING, e.toString());
} }
} }
} }
@ -116,12 +116,12 @@ public class PrefixFileReader {
int countryCallingCode = number.getCountryCode(); int countryCallingCode = number.getCountryCode();
// As the NANPA data is split into multiple files covering 3-digit areas, use a phone number // As the NANPA data is split into multiple files covering 3-digit areas, use a phone number
// prefix of 4 digits for NANPA instead, e.g. 1650. // prefix of 4 digits for NANPA instead, e.g. 1650.
int phonePrefix = (countryCallingCode != 1) ?
countryCallingCode : (1000 + (int) (number.getNationalNumber() / 10000000));
int phonePrefix = (countryCallingCode != 1)
? countryCallingCode : (1000 + (int) (number.getNationalNumber() / 10000000));
PhonePrefixMap phonePrefixDescriptions = PhonePrefixMap phonePrefixDescriptions =
getPhonePrefixDescriptions(phonePrefix, lang, script, region); getPhonePrefixDescriptions(phonePrefix, lang, script, region);
String description = (phonePrefixDescriptions != null) ?
phonePrefixDescriptions.lookup(number) : null;
String description = (phonePrefixDescriptions != null)
? phonePrefixDescriptions.lookup(number) : null;
// When a location is not available in the requested language, fall back to English. // When a location is not available in the requested language, fall back to English.
if ((description == null || description.length() == 0) && mayFallBackToEnglish(lang)) { if ((description == null || description.length() == 0) && mayFallBackToEnglish(lang)) {
PhonePrefixMap defaultMap = getPhonePrefixDescriptions(phonePrefix, "en", "", ""); PhonePrefixMap defaultMap = getPhonePrefixDescriptions(phonePrefix, "en", "", "");


+ 2
- 2
java/internal/prefixmapper/src/com/google/i18n/phonenumbers/prefixmapper/PrefixTimeZonesMap.java View File

@ -88,8 +88,8 @@ public class PrefixTimeZonesMap implements Externalizable {
* @return the list of corresponding time zones * @return the list of corresponding time zones
*/ */
public List<String> lookupTimeZonesForNumber(PhoneNumber number) { public List<String> lookupTimeZonesForNumber(PhoneNumber number) {
long phonePrefix = Long.parseLong(number.getCountryCode() +
PhoneNumberUtil.getInstance().getNationalSignificantNumber(number));
long phonePrefix = Long.parseLong(number.getCountryCode()
+ PhoneNumberUtil.getInstance().getNationalSignificantNumber(number));
return lookupTimeZonesForNumber(phonePrefix); return lookupTimeZonesForNumber(phonePrefix);
} }


+ 2
- 2
java/internal/prefixmapper/test/com/google/i18n/phonenumbers/prefixmapper/MappingFileProviderTest.java View File

@ -38,7 +38,7 @@ import java.util.logging.Logger;
*/ */
public class MappingFileProviderTest extends TestCase { public class MappingFileProviderTest extends TestCase {
private final MappingFileProvider mappingProvider = new MappingFileProvider(); private final MappingFileProvider mappingProvider = new MappingFileProvider();
private static final Logger LOGGER = Logger.getLogger(MappingFileProviderTest.class.getName());
private static final Logger logger = Logger.getLogger(MappingFileProviderTest.class.getName());
public MappingFileProviderTest() { public MappingFileProviderTest() {
SortedMap<Integer, Set<String>> mapping = new TreeMap<Integer, Set<String>>(); SortedMap<Integer, Set<String>> mapping = new TreeMap<Integer, Set<String>>();
@ -68,7 +68,7 @@ public class MappingFileProviderTest extends TestCase {
new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()))); new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())));
assertEquals(mappingProvider.toString(), newMappingProvider.toString()); assertEquals(mappingProvider.toString(), newMappingProvider.toString());
} catch (IOException e) { } catch (IOException e) {
LOGGER.log(Level.SEVERE, e.getMessage());
logger.log(Level.SEVERE, e.getMessage());
fail(); fail();
} }
} }


+ 21
- 18
java/libphonenumber/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java View File

@ -82,8 +82,8 @@ public class AsYouTypeFormatter {
// prevents invalid punctuation (such as the star sign in Israeli star numbers) getting into the // prevents invalid punctuation (such as the star sign in Israeli star numbers) getting into the
// output of the AYTF. // output of the AYTF.
private static final Pattern ELIGIBLE_FORMAT_PATTERN = private static final Pattern ELIGIBLE_FORMAT_PATTERN =
Pattern.compile("[" + PhoneNumberUtil.VALID_PUNCTUATION + "]*" +
"(\\$\\d" + "[" + PhoneNumberUtil.VALID_PUNCTUATION + "]*)+");
Pattern.compile("[" + PhoneNumberUtil.VALID_PUNCTUATION + "]*"
+ "(\\$\\d" + "[" + PhoneNumberUtil.VALID_PUNCTUATION + "]*)+");
// A set of characters that, if found in a national prefix formatting rules, are an indicator to // A set of characters that, if found in a national prefix formatting rules, are an indicator to
// us that we should separate the national prefix from the number when formatting. // us that we should separate the national prefix from the number when formatting.
private static final Pattern NATIONAL_PREFIX_SEPARATORS_PATTERN = Pattern.compile("[- ]"); private static final Pattern NATIONAL_PREFIX_SEPARATORS_PATTERN = Pattern.compile("[- ]");
@ -179,9 +179,10 @@ public class AsYouTypeFormatter {
: currentMetadata.numberFormats(); : currentMetadata.numberFormats();
boolean nationalPrefixIsUsedByCountry = currentMetadata.hasNationalPrefix(); boolean nationalPrefixIsUsedByCountry = currentMetadata.hasNationalPrefix();
for (NumberFormat format : formatList) { for (NumberFormat format : formatList) {
if (!nationalPrefixIsUsedByCountry || isCompleteNumber ||
format.isNationalPrefixOptionalWhenFormatting() ||
PhoneNumberUtil.formattingRuleHasFirstGroupOnly(
if (!nationalPrefixIsUsedByCountry
|| isCompleteNumber
|| format.isNationalPrefixOptionalWhenFormatting()
|| PhoneNumberUtil.formattingRuleHasFirstGroupOnly(
format.getNationalPrefixFormattingRule())) { format.getNationalPrefixFormattingRule())) {
if (isFormatEligible(format.getFormat())) { if (isFormatEligible(format.getFormat())) {
possibleFormats.add(format); possibleFormats.add(format);
@ -358,6 +359,7 @@ public class AsYouTypeFormatter {
extractedNationalPrefix = removeNationalPrefixFromNationalNumber(); extractedNationalPrefix = removeNationalPrefixFromNationalNumber();
return attemptToChooseFormattingPattern(); return attemptToChooseFormattingPattern();
} }
// fall through
default: default:
if (isExpectingCountryCallingCode) { if (isExpectingCountryCallingCode) {
if (attemptToExtractCountryCallingCode()) { if (attemptToExtractCountryCallingCode()) {
@ -417,13 +419,13 @@ public class AsYouTypeFormatter {
} }
private boolean isDigitOrLeadingPlusSign(char nextChar) { private boolean isDigitOrLeadingPlusSign(char nextChar) {
return Character.isDigit(nextChar) ||
(accruedInput.length() == 1 &&
PhoneNumberUtil.PLUS_CHARS_PATTERN.matcher(Character.toString(nextChar)).matches());
return Character.isDigit(nextChar)
|| (accruedInput.length() == 1
&& PhoneNumberUtil.PLUS_CHARS_PATTERN.matcher(Character.toString(nextChar)).matches());
} }
/** /**
* Check to see if there is an exact pattern match for these digits. If so, we should use this
* Checks to see if there is an exact pattern match for these digits. If so, we should use this
* instead of any other formatting template whose leadingDigitsPattern also matches the input. * instead of any other formatting template whose leadingDigitsPattern also matches the input.
*/ */
String attemptToFormatAccruedDigits() { String attemptToFormatAccruedDigits() {
@ -448,10 +450,11 @@ public class AsYouTypeFormatter {
if (!ableToFormat) { if (!ableToFormat) {
return originalPosition; return originalPosition;
} }
int accruedInputIndex = 0, currentOutputIndex = 0;
int accruedInputIndex = 0;
int currentOutputIndex = 0;
while (accruedInputIndex < positionToRemember && currentOutputIndex < currentOutput.length()) { while (accruedInputIndex < positionToRemember && currentOutputIndex < currentOutput.length()) {
if (accruedInputWithoutFormatting.charAt(accruedInputIndex) ==
currentOutput.charAt(currentOutputIndex)) {
if (accruedInputWithoutFormatting.charAt(accruedInputIndex)
== currentOutput.charAt(currentOutputIndex)) {
accruedInputIndex++; accruedInputIndex++;
} }
currentOutputIndex++; currentOutputIndex++;
@ -466,8 +469,8 @@ public class AsYouTypeFormatter {
*/ */
private String appendNationalNumber(String nationalNumber) { private String appendNationalNumber(String nationalNumber) {
int prefixBeforeNationalNumberLength = prefixBeforeNationalNumber.length(); int prefixBeforeNationalNumberLength = prefixBeforeNationalNumber.length();
if (shouldAddSpaceAfterNationalPrefix && prefixBeforeNationalNumberLength > 0 &&
prefixBeforeNationalNumber.charAt(prefixBeforeNationalNumberLength - 1)
if (shouldAddSpaceAfterNationalPrefix && prefixBeforeNationalNumberLength > 0
&& prefixBeforeNationalNumber.charAt(prefixBeforeNationalNumberLength - 1)
!= SEPARATOR_BEFORE_NATIONAL_NUMBER) { != SEPARATOR_BEFORE_NATIONAL_NUMBER) {
// We want to add a space after the national prefix if the national prefix formatting rule // We want to add a space after the national prefix if the national prefix formatting rule
// indicates that this would normally be done, with the exception of the case where we already // indicates that this would normally be done, with the exception of the case where we already
@ -526,8 +529,8 @@ public class AsYouTypeFormatter {
// that national significant numbers in NANPA always start with [2-9] after the national prefix. // that national significant numbers in NANPA always start with [2-9] after the national prefix.
// Numbers beginning with 1[01] can only be short/emergency numbers, which don't need the // Numbers beginning with 1[01] can only be short/emergency numbers, which don't need the
// national prefix. // national prefix.
return (currentMetadata.getCountryCode() == 1) && (nationalNumber.charAt(0) == '1') &&
(nationalNumber.charAt(1) != '0') && (nationalNumber.charAt(1) != '1');
return (currentMetadata.getCountryCode() == 1) && (nationalNumber.charAt(0) == '1')
&& (nationalNumber.charAt(1) != '0') && (nationalNumber.charAt(1) != '1');
} }
// Returns the national prefix extracted, or an empty string if it is not present. // Returns the national prefix extracted, or an empty string if it is not present.
@ -566,8 +569,8 @@ public class AsYouTypeFormatter {
*/ */
private boolean attemptToExtractIdd() { private boolean attemptToExtractIdd() {
Pattern internationalPrefix = Pattern internationalPrefix =
regexCache.getPatternForRegex("\\" + PhoneNumberUtil.PLUS_SIGN + "|" +
currentMetadata.getInternationalPrefix());
regexCache.getPatternForRegex("\\" + PhoneNumberUtil.PLUS_SIGN + "|"
+ currentMetadata.getInternationalPrefix());
Matcher iddMatcher = internationalPrefix.matcher(accruedInputWithoutFormatting); Matcher iddMatcher = internationalPrefix.matcher(accruedInputWithoutFormatting);
if (iddMatcher.lookingAt()) { if (iddMatcher.lookingAt()) {
isCompleteNumber = true; isCompleteNumber = true;


+ 1
- 0
java/libphonenumber/src/com/google/i18n/phonenumbers/MetadataSource.java View File

@ -22,6 +22,7 @@ import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
* A source for phone metadata for all regions. * A source for phone metadata for all regions.
*/ */
interface MetadataSource { interface MetadataSource {
/** /**
* Gets phone metadata for a region. * Gets phone metadata for a region.
* @param regionCode the region code. * @param regionCode the region code.


+ 23
- 9
java/libphonenumber/src/com/google/i18n/phonenumbers/NumberParseException.java View File

@ -22,20 +22,34 @@ package com.google.i18n.phonenumbers;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class NumberParseException extends Exception { public class NumberParseException extends Exception {
/**
* The reason that a string could not be interpreted as a phone number.
*/
public enum ErrorType { public enum ErrorType {
/**
* The country code supplied did not belong to a supported country or non-geographical entity.
*/
INVALID_COUNTRY_CODE, INVALID_COUNTRY_CODE,
// This generally indicates the string passed in had less than 3 digits in it. More
// specifically, the number failed to match the regular expression VALID_PHONE_NUMBER in
// PhoneNumberUtil.java.
/**
* This generally indicates the string passed in had less than 3 digits in it. More
* specifically, the number failed to match the regular expression VALID_PHONE_NUMBER in
* PhoneNumberUtil.java.
*/
NOT_A_NUMBER, NOT_A_NUMBER,
// This indicates the string started with an international dialing prefix, but after this was
// stripped from the number, had less digits than any valid phone number (including country
// code) could have.
/**
* This indicates the string started with an international dialing prefix, but after this was
* stripped from the number, had less digits than any valid phone number (including country
* code) could have.
*/
TOO_SHORT_AFTER_IDD, TOO_SHORT_AFTER_IDD,
// This indicates the string, after any country code has been stripped, had less digits than any
// valid phone number could have.
/**
* This indicates the string, after any country code has been stripped, had less digits than any
* valid phone number could have.
*/
TOO_SHORT_NSN, TOO_SHORT_NSN,
// This indicates the string had more digits than any valid phone number could have.
/**
* This indicates the string had more digits than any valid phone number could have.
*/
TOO_LONG, TOO_LONG,
} }


+ 2
- 2
java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberMatch.java View File

@ -112,8 +112,8 @@ public final class PhoneNumberMatch {
return false; return false;
} }
PhoneNumberMatch other = (PhoneNumberMatch) obj; PhoneNumberMatch other = (PhoneNumberMatch) obj;
return rawString.equals(other.rawString) && (start == other.start) &&
number.equals(other.number);
return rawString.equals(other.rawString) && (start == other.start)
&& number.equals(other.number);
} }
@Override @Override


+ 34
- 34
java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberMatcher.java View File

@ -138,10 +138,10 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
* closing bracket first. We limit the sets of brackets in a phone number to four. * closing bracket first. We limit the sets of brackets in a phone number to four.
*/ */
MATCHING_BRACKETS = Pattern.compile( MATCHING_BRACKETS = Pattern.compile(
"(?:[" + openingParens + "])?" + "(?:" + nonParens + "+" + "[" + closingParens + "])?" +
nonParens + "+" +
"(?:[" + openingParens + "]" + nonParens + "+[" + closingParens + "])" + bracketPairLimit +
nonParens + "*");
"(?:[" + openingParens + "])?" + "(?:" + nonParens + "+" + "[" + closingParens + "])?"
+ nonParens + "+"
+ "(?:[" + openingParens + "]" + nonParens + "+[" + closingParens + "])" + bracketPairLimit
+ nonParens + "*");
/* Limit on the number of leading (plus) characters. */ /* Limit on the number of leading (plus) characters. */
String leadLimit = limit(0, 2); String leadLimit = limit(0, 2);
@ -167,9 +167,9 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
/* Phone number pattern allowing optional punctuation. */ /* Phone number pattern allowing optional punctuation. */
PATTERN = Pattern.compile( PATTERN = Pattern.compile(
"(?:" + leadClass + punctuation + ")" + leadLimit +
digitSequence + "(?:" + punctuation + digitSequence + ")" + blockLimit +
"(?:" + PhoneNumberUtil.EXTN_PATTERNS_FOR_MATCHING + ")?",
"(?:" + leadClass + punctuation + ")" + leadLimit
+ digitSequence + "(?:" + punctuation + digitSequence + ")" + blockLimit
+ "(?:" + PhoneNumberUtil.EXTN_PATTERNS_FOR_MATCHING + ")?",
PhoneNumberUtil.REGEX_FLAGS); PhoneNumberUtil.REGEX_FLAGS);
} }
@ -211,16 +211,16 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
* Creates a new instance. See the factory methods in {@link PhoneNumberUtil} on how to obtain a * Creates a new instance. See the factory methods in {@link PhoneNumberUtil} on how to obtain a
* new instance. * new instance.
* *
* @param util the phone number util to use
* @param text the character sequence that we will search, null for no text
* @param country the country to assume for phone numbers not written in international format
* (with a leading plus, or with the international dialing prefix of the
* specified region). May be null or "ZZ" if only numbers with a
* leading plus should be considered.
* @param util the phone number util to use
* @param text the character sequence that we will search, null for no text
* @param country the country to assume for phone numbers not written in international format
* (with a leading plus, or with the international dialing prefix of the specified region).
* May be null or "ZZ" if only numbers with a leading plus should be
* considered.
* @param leniency the leniency to use when evaluating candidate phone numbers * @param leniency the leniency to use when evaluating candidate phone numbers
* @param maxTries the maximum number of invalid numbers to try before giving up on the text. * @param maxTries the maximum number of invalid numbers to try before giving up on the text.
* This is to cover degenerate cases where the text has a lot of false positives
* in it. Must be {@code >= 0}.
* This is to cover degenerate cases where the text has a lot of false positives in it. Must
* be {@code >= 0}.
*/ */
PhoneNumberMatcher(PhoneNumberUtil util, CharSequence text, String country, Leniency leniency, PhoneNumberMatcher(PhoneNumberUtil util, CharSequence text, String country, Leniency leniency,
long maxTries) { long maxTries) {
@ -292,12 +292,12 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
return false; return false;
} }
UnicodeBlock block = UnicodeBlock.of(letter); UnicodeBlock block = UnicodeBlock.of(letter);
return block.equals(UnicodeBlock.BASIC_LATIN) ||
block.equals(UnicodeBlock.LATIN_1_SUPPLEMENT) ||
block.equals(UnicodeBlock.LATIN_EXTENDED_A) ||
block.equals(UnicodeBlock.LATIN_EXTENDED_ADDITIONAL) ||
block.equals(UnicodeBlock.LATIN_EXTENDED_B) ||
block.equals(UnicodeBlock.COMBINING_DIACRITICAL_MARKS);
return block.equals(UnicodeBlock.BASIC_LATIN)
|| block.equals(UnicodeBlock.LATIN_1_SUPPLEMENT)
|| block.equals(UnicodeBlock.LATIN_EXTENDED_A)
|| block.equals(UnicodeBlock.LATIN_EXTENDED_ADDITIONAL)
|| block.equals(UnicodeBlock.LATIN_EXTENDED_B)
|| block.equals(UnicodeBlock.COMBINING_DIACRITICAL_MARKS);
} }
private static boolean isInvalidPunctuationSymbol(char character) { private static boolean isInvalidPunctuationSymbol(char character) {
@ -426,9 +426,9 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
// TODO: Remove this or make it significantly less hacky once we've decided how to // TODO: Remove this or make it significantly less hacky once we've decided how to
// handle these short codes going forward in ShortNumberInfo. We could use the formatting // handle these short codes going forward in ShortNumberInfo. We could use the formatting
// rules for instance, but that would be slower. // rules for instance, but that would be slower.
if (phoneUtil.getRegionCodeForCountryCode(number.getCountryCode()).equals("IL") &&
phoneUtil.getNationalSignificantNumber(number).length() == 4 &&
(offset == 0 || (offset > 0 && text.charAt(offset - 1) != '*'))) {
if (phoneUtil.getRegionCodeForCountryCode(number.getCountryCode()).equals("IL")
&& phoneUtil.getNationalSignificantNumber(number).length() == 4
&& (offset == 0 || (offset > 0 && text.charAt(offset - 1) != '*'))) {
// No match. // No match.
return null; return null;
} }
@ -495,8 +495,8 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
// as we do not need to distinguish between different countries with the same country // as we do not need to distinguish between different countries with the same country
// calling code and this is faster. // calling code and this is faster.
String region = util.getRegionCodeForCountryCode(number.getCountryCode()); String region = util.getRegionCodeForCountryCode(number.getCountryCode());
if (util.getNddPrefixForRegion(region, true) != null &&
Character.isDigit(normalizedCandidate.charAt(fromIndex))) {
if (util.getNddPrefixForRegion(region, true) != null
&& Character.isDigit(normalizedCandidate.charAt(fromIndex))) {
// This means there is no formatting symbol after the NDC. In this case, we only // This means there is no formatting symbol after the NDC. In this case, we only
// accept the number if there is no formatting symbol at all in the number, except // accept the number if there is no formatting symbol at all in the number, except
// for extensions. This is only important for countries with national prefixes. // for extensions. This is only important for countries with national prefixes.
@ -524,8 +524,8 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
// First we check if the national significant number is formatted as a block. // First we check if the national significant number is formatted as a block.
// We use contains and not equals, since the national significant number may be present with // We use contains and not equals, since the national significant number may be present with
// a prefix such as a national number prefix, or the country code itself. // a prefix such as a national number prefix, or the country code itself.
if (candidateGroups.length == 1 ||
candidateGroups[candidateNumberGroupIndex].contains(
if (candidateGroups.length == 1
|| candidateGroups[candidateNumberGroupIndex].contains(
util.getNationalSignificantNumber(number))) { util.getNationalSignificantNumber(number))) {
return true; return true;
} }
@ -541,8 +541,8 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
} }
// Now check the first group. There may be a national prefix at the start, so we only check // Now check the first group. There may be a national prefix at the start, so we only check
// that the candidate group ends with the formatted number group. // that the candidate group ends with the formatted number group.
return (candidateNumberGroupIndex >= 0 &&
candidateGroups[candidateNumberGroupIndex].endsWith(formattedNumberGroups[0]));
return (candidateNumberGroupIndex >= 0
&& candidateGroups[candidateNumberGroupIndex].endsWith(formattedNumberGroups[0]));
} }
/** /**
@ -610,10 +610,10 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
// If the first slash is after the country calling code, this is permitted. // If the first slash is after the country calling code, this is permitted.
boolean candidateHasCountryCode = boolean candidateHasCountryCode =
(number.getCountryCodeSource() == CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN ||
number.getCountryCodeSource() == CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN);
if (candidateHasCountryCode &&
PhoneNumberUtil.normalizeDigitsOnly(candidate.substring(0, firstSlashInBodyIndex))
(number.getCountryCodeSource() == CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN
|| number.getCountryCodeSource() == CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN);
if (candidateHasCountryCode
&& PhoneNumberUtil.normalizeDigitsOnly(candidate.substring(0, firstSlashInBodyIndex))
.equals(Integer.toString(number.getCountryCode()))) { .equals(Integer.toString(number.getCountryCode()))) {
// Any more slashes and this is illegal. // Any more slashes and this is illegal.
return candidate.substring(secondSlashInBodyIndex + 1).contains("/"); return candidate.substring(secondSlashInBodyIndex + 1).contains("/");


+ 163
- 168
java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java View File

@ -241,14 +241,15 @@ public class PhoneNumberUtil {
// square brackets, parentheses and tildes. It also includes the letter 'x' as that is found as a // square brackets, parentheses and tildes. It also includes the letter 'x' as that is found as a
// placeholder for carrier information in some phone numbers. Full-width variants are also // placeholder for carrier information in some phone numbers. Full-width variants are also
// present. // present.
static final String VALID_PUNCTUATION = "-x\u2010-\u2015\u2212\u30FC\uFF0D-\uFF0F " +
"\u00A0\u00AD\u200B\u2060\u3000()\uFF08\uFF09\uFF3B\uFF3D.\\[\\]/~\u2053\u223C\uFF5E";
static final String VALID_PUNCTUATION = "-x\u2010-\u2015\u2212\u30FC\uFF0D-\uFF0F "
+ "\u00A0\u00AD\u200B\u2060\u3000()\uFF08\uFF09\uFF3B\uFF3D.\\[\\]/~\u2053\u223C\uFF5E";
private static final String DIGITS = "\\p{Nd}"; private static final String DIGITS = "\\p{Nd}";
// We accept alpha characters in phone numbers, ASCII only, upper and lower case. // We accept alpha characters in phone numbers, ASCII only, upper and lower case.
private static final String VALID_ALPHA = private static final String VALID_ALPHA =
Arrays.toString(ALPHA_MAPPINGS.keySet().toArray()).replaceAll("[, \\[\\]]", "") +
Arrays.toString(ALPHA_MAPPINGS.keySet().toArray()).toLowerCase().replaceAll("[, \\[\\]]", "");
Arrays.toString(ALPHA_MAPPINGS.keySet().toArray()).replaceAll("[, \\[\\]]", "")
+ Arrays.toString(ALPHA_MAPPINGS.keySet().toArray())
.toLowerCase().replaceAll("[, \\[\\]]", "");
static final String PLUS_CHARS = "+\uFF0B"; static final String PLUS_CHARS = "+\uFF0B";
static final Pattern PLUS_CHARS_PATTERN = Pattern.compile("[" + PLUS_CHARS + "]+"); static final Pattern PLUS_CHARS_PATTERN = Pattern.compile("[" + PLUS_CHARS + "]+");
private static final Pattern SEPARATOR_PATTERN = Pattern.compile("[" + VALID_PUNCTUATION + "]+"); private static final Pattern SEPARATOR_PATTERN = Pattern.compile("[" + VALID_PUNCTUATION + "]+");
@ -298,9 +299,9 @@ public class PhoneNumberUtil {
// //
// Note VALID_PUNCTUATION starts with a -, so must be the first in the range. // Note VALID_PUNCTUATION starts with a -, so must be the first in the range.
private static final String VALID_PHONE_NUMBER = private static final String VALID_PHONE_NUMBER =
DIGITS + "{" + MIN_LENGTH_FOR_NSN + "}" + "|" +
"[" + PLUS_CHARS + "]*+(?:[" + VALID_PUNCTUATION + STAR_SIGN + "]*" + DIGITS + "){3,}[" +
VALID_PUNCTUATION + STAR_SIGN + VALID_ALPHA + DIGITS + "]*";
DIGITS + "{" + MIN_LENGTH_FOR_NSN + "}" + "|"
+ "[" + PLUS_CHARS + "]*+(?:[" + VALID_PUNCTUATION + STAR_SIGN + "]*" + DIGITS + "){3,}["
+ VALID_PUNCTUATION + STAR_SIGN + VALID_ALPHA + DIGITS + "]*";
// Default extension prefix to use when formatting. This will be put in front of any extension // Default extension prefix to use when formatting. This will be put in front of any extension
// component of the number, after the main national number is formatted. For example, if you wish // component of the number, after the main national number is formatted. For example, if you wish
@ -343,11 +344,11 @@ public class PhoneNumberUtil {
// Canonical-equivalence doesn't seem to be an option with Android java, so we allow two options // Canonical-equivalence doesn't seem to be an option with Android java, so we allow two options
// for representing the accented o - the character itself, and one in the unicode decomposed // for representing the accented o - the character itself, and one in the unicode decomposed
// form with the combining acute accent. // form with the combining acute accent.
return (RFC3966_EXTN_PREFIX + CAPTURING_EXTN_DIGITS + "|" + "[ \u00A0\\t,]*" +
"(?:e?xt(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45?\uFF58\uFF54\uFF4E?|" +
"[" + singleExtnSymbols + "]|int|anexo|\uFF49\uFF4E\uFF54)" +
"[:\\.\uFF0E]?[ \u00A0\\t,-]*" + CAPTURING_EXTN_DIGITS + "#?|" +
"[- ]+(" + DIGITS + "{1,5})#");
return (RFC3966_EXTN_PREFIX + CAPTURING_EXTN_DIGITS + "|" + "[ \u00A0\\t,]*"
+ "(?:e?xt(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45?\uFF58\uFF54\uFF4E?|"
+ "[" + singleExtnSymbols + "]|int|anexo|\uFF49\uFF4E\uFF54)"
+ "[:\\.\uFF0E]?[ \u00A0\\t,-]*" + CAPTURING_EXTN_DIGITS + "#?|"
+ "[- ]+(" + DIGITS + "{1,5})#");
} }
// Regexp of all known extension prefixes used by different regions followed by 1 or more valid // Regexp of all known extension prefixes used by different regions followed by 1 or more valid
@ -477,8 +478,8 @@ public class PhoneNumberUtil {
VALID { VALID {
@Override @Override
boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) { boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) {
if (!util.isValidNumber(number) ||
!PhoneNumberMatcher.containsOnlyValidXChars(number, candidate, util)) {
if (!util.isValidNumber(number)
|| !PhoneNumberMatcher.containsOnlyValidXChars(number, candidate, util)) {
return false; return false;
} }
return PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util); return PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util);
@ -499,10 +500,10 @@ public class PhoneNumberUtil {
STRICT_GROUPING { STRICT_GROUPING {
@Override @Override
boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) { boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) {
if (!util.isValidNumber(number) ||
!PhoneNumberMatcher.containsOnlyValidXChars(number, candidate, util) ||
PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate) ||
!PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util)) {
if (!util.isValidNumber(number)
|| !PhoneNumberMatcher.containsOnlyValidXChars(number, candidate, util)
|| PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)
|| !PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util)) {
return false; return false;
} }
return PhoneNumberMatcher.checkNumberGroupingIsValid( return PhoneNumberMatcher.checkNumberGroupingIsValid(
@ -531,10 +532,10 @@ public class PhoneNumberUtil {
EXACT_GROUPING { EXACT_GROUPING {
@Override @Override
boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) { boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) {
if (!util.isValidNumber(number) ||
!PhoneNumberMatcher.containsOnlyValidXChars(number, candidate, util) ||
PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate) ||
!PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util)) {
if (!util.isValidNumber(number)
|| !PhoneNumberMatcher.containsOnlyValidXChars(number, candidate, util)
|| PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)
|| !PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util)) {
return false; return false;
} }
return PhoneNumberMatcher.checkNumberGroupingIsValid( return PhoneNumberMatcher.checkNumberGroupingIsValid(
@ -606,8 +607,8 @@ public class PhoneNumberUtil {
// there are entries that list the non-geo entity alongside normal regions (which is wrong). // there are entries that list the non-geo entity alongside normal regions (which is wrong).
// If we discover this, remove the non-geo entity from the set of supported regions and log. // If we discover this, remove the non-geo entity from the set of supported regions and log.
if (supportedRegions.remove(REGION_CODE_FOR_NON_GEO_ENTITY)) { if (supportedRegions.remove(REGION_CODE_FOR_NON_GEO_ENTITY)) {
logger.log(Level.WARNING, "invalid metadata " +
"(country calling code was mapped to the non-geo entity as well as specific region(s))");
logger.log(Level.WARNING, "invalid metadata (country calling code was mapped to the non-geo "
+ "entity as well as specific region(s))");
} }
nanpaRegions.addAll(countryCallingCodeToRegionCodeMap.get(NANPA_COUNTRY_CODE)); nanpaRegions.addAll(countryCallingCodeToRegionCodeMap.get(NANPA_COUNTRY_CODE));
} }
@ -623,9 +624,9 @@ public class PhoneNumberUtil {
* number is parsed correctly. * number is parsed correctly.
* *
* @param number the string that might contain a phone number * @param number the string that might contain a phone number
* @return the number, stripped of any non-phone-number prefix (such as "Tel:") or an empty
* string if no character used to start phone numbers (such as + or any digit) is
* found in the number
* @return the number, stripped of any non-phone-number prefix (such as "Tel:") or an empty
* string if no character used to start phone numbers (such as + or any digit) is found in the
* number
*/ */
static String extractPossibleNumber(String number) { static String extractPossibleNumber(String number) {
Matcher m = VALID_START_CHAR_PATTERN.matcher(number); Matcher m = VALID_START_CHAR_PATTERN.matcher(number);
@ -656,7 +657,7 @@ public class PhoneNumberUtil {
* leading non-number symbols have been removed, such as by the method extractPossibleNumber. * leading non-number symbols have been removed, such as by the method extractPossibleNumber.
* *
* @param number string to be checked for viability as a phone number * @param number string to be checked for viability as a phone number
* @return true if the number could be a phone number of some sort, otherwise false
* @return true if the number could be a phone number of some sort, otherwise false
*/ */
// @VisibleForTesting // @VisibleForTesting
static boolean isViablePhoneNumber(String number) { static boolean isViablePhoneNumber(String number) {
@ -681,7 +682,7 @@ public class PhoneNumberUtil {
* Spurious alpha characters are stripped. * Spurious alpha characters are stripped.
* *
* @param number a string of characters representing a phone number * @param number a string of characters representing a phone number
* @return the normalized string version of the phone number
* @return the normalized string version of the phone number
*/ */
static String normalize(String number) { static String normalize(String number) {
Matcher m = VALID_ALPHA_PHONE_PATTERN.matcher(number); Matcher m = VALID_ALPHA_PHONE_PATTERN.matcher(number);
@ -709,7 +710,7 @@ public class PhoneNumberUtil {
* arabic-indic numerals to European numerals, and strips punctuation and alpha characters. * arabic-indic numerals to European numerals, and strips punctuation and alpha characters.
* *
* @param number a string of characters representing a phone number * @param number a string of characters representing a phone number
* @return the normalized string version of the phone number
* @return the normalized string version of the phone number
*/ */
public static String normalizeDigitsOnly(String number) { public static String normalizeDigitsOnly(String number) {
return normalizeDigits(number, false /* strip non-digits */).toString(); return normalizeDigits(number, false /* strip non-digits */).toString();
@ -733,7 +734,7 @@ public class PhoneNumberUtil {
* are not diallable on a mobile phone keypad (including all non-ASCII digits). * are not diallable on a mobile phone keypad (including all non-ASCII digits).
* *
* @param number a string of characters representing a phone number * @param number a string of characters representing a phone number
* @return the normalized string version of the phone number
* @return the normalized string version of the phone number
*/ */
static String normalizeDiallableCharsOnly(String number) { static String normalizeDiallableCharsOnly(String number) {
return normalizeHelper(number, DIALLABLE_CHAR_MAPPINGS, true /* remove non matches */); return normalizeHelper(number, DIALLABLE_CHAR_MAPPINGS, true /* remove non matches */);
@ -784,9 +785,9 @@ public class PhoneNumberUtil {
* <li> some geographical numbers have no area codes. * <li> some geographical numbers have no area codes.
* </ul> * </ul>
* @param number the PhoneNumber object for which clients * @param number the PhoneNumber object for which clients
* want to know the length of the area code.
* want to know the length of the area code
* @return the length of area code of the PhoneNumber object * @return the length of area code of the PhoneNumber object
* passed in.
* passed in
*/ */
public int getLengthOfGeographicalAreaCode(PhoneNumber number) { public int getLengthOfGeographicalAreaCode(PhoneNumber number) {
PhoneMetadata metadata = getMetadataForRegion(getRegionCodeForNumber(number)); PhoneMetadata metadata = getMetadataForRegion(getRegionCodeForNumber(number));
@ -846,9 +847,9 @@ public class PhoneNumberUtil {
* {@link #getLengthOfGeographicalAreaCode}. * {@link #getLengthOfGeographicalAreaCode}.
* *
* @param number the PhoneNumber object for which clients * @param number the PhoneNumber object for which clients
* want to know the length of the NDC.
* want to know the length of the NDC
* @return the length of NDC of the PhoneNumber object * @return the length of NDC of the PhoneNumber object
* passed in.
* passed in
*/ */
public int getLengthOfNationalDestinationCode(PhoneNumber number) { public int getLengthOfNationalDestinationCode(PhoneNumber number) {
PhoneNumber copiedProto; PhoneNumber copiedProto;
@ -906,12 +907,11 @@ public class PhoneNumberUtil {
* in the accompanying map with the values therein, and stripping all other characters if * in the accompanying map with the values therein, and stripping all other characters if
* removeNonMatches is true. * removeNonMatches is true.
* *
* @param number a string of characters representing a phone number
* @param number a string of characters representing a phone number
* @param normalizationReplacements a mapping of characters to what they should be replaced by in * @param normalizationReplacements a mapping of characters to what they should be replaced by in
* the normalized version of the phone number
* @param removeNonMatches indicates whether characters that are not able to be replaced
* should be stripped from the number. If this is false, they
* will be left unchanged in the number.
* the normalized version of the phone number
* @param removeNonMatches indicates whether characters that are not able to be replaced should
* be stripped from the number. If this is false, they will be left unchanged in the number.
* @return the normalized string version of the phone number * @return the normalized string version of the phone number
*/ */
private static String normalizeHelper(String number, private static String normalizeHelper(String number,
@ -977,12 +977,12 @@ public class PhoneNumberUtil {
* formatting, parsing, or validation. The instance is loaded with all metadata by * formatting, parsing, or validation. The instance is loaded with all metadata by
* using the metadataSource specified. * using the metadataSource specified.
* *
* This method should only be used in the rare case in which you want to manage your own
* <p>This method should only be used in the rare case in which you want to manage your own
* metadata loading. Calling this method multiple times is very expensive, as each time * metadata loading. Calling this method multiple times is very expensive, as each time
* a new instance is created from scratch. When in doubt, use {@link #getInstance}. * a new instance is created from scratch. When in doubt, use {@link #getInstance}.
* *
* @param metadataSource Customized metadata source. This should not be null.
* @return a PhoneNumberUtil instance
* @param metadataSource customized metadata source. This should not be null.
* @return a PhoneNumberUtil instance
*/ */
public static PhoneNumberUtil createInstance(MetadataSource metadataSource) { public static PhoneNumberUtil createInstance(MetadataSource metadataSource) {
if (metadataSource == null) { if (metadataSource == null) {
@ -1016,8 +1016,8 @@ public class PhoneNumberUtil {
* does not start with the national prefix. * does not start with the national prefix.
*/ */
static boolean formattingRuleHasFirstGroupOnly(String nationalPrefixFormattingRule) { static boolean formattingRuleHasFirstGroupOnly(String nationalPrefixFormattingRule) {
return nationalPrefixFormattingRule.length() == 0 ||
FIRST_GROUP_ONLY_PREFIX_PATTERN.matcher(nationalPrefixFormattingRule).matches();
return nationalPrefixFormattingRule.length() == 0
|| FIRST_GROUP_ONLY_PREFIX_PATTERN.matcher(nationalPrefixFormattingRule).matches();
} }
/** /**
@ -1067,8 +1067,8 @@ public class PhoneNumberUtil {
* which formatting rules to apply so we return the national significant number with no formatting * which formatting rules to apply so we return the national significant number with no formatting
* applied. * applied.
* *
* @param number the phone number to be formatted
* @param numberFormat the format the phone number should be formatted into
* @param number the phone number to be formatted
* @param numberFormat the format the phone number should be formatted into
* @return the formatted phone number * @return the formatted phone number
*/ */
public String format(PhoneNumber number, PhoneNumberFormat numberFormat) { public String format(PhoneNumber number, PhoneNumberFormat numberFormat) {
@ -1130,9 +1130,9 @@ public class PhoneNumberUtil {
* code, we cannot work out things like whether there should be a national prefix applied, or how * code, we cannot work out things like whether there should be a national prefix applied, or how
* to format extensions, so we return the national significant number with no formatting applied. * to format extensions, so we return the national significant number with no formatting applied.
* *
* @param number the phone number to be formatted
* @param numberFormat the format the phone number should be formatted into
* @param userDefinedFormats formatting rules specified by clients
* @param number the phone number to be formatted
* @param numberFormat the format the phone number should be formatted into
* @param userDefinedFormats formatting rules specified by clients
* @return the formatted phone number * @return the formatted phone number
*/ */
public String formatByPattern(PhoneNumber number, public String formatByPattern(PhoneNumber number,
@ -1196,7 +1196,7 @@ public class PhoneNumberUtil {
* @param number the phone number to be formatted * @param number the phone number to be formatted
* @param carrierCode the carrier selection code to be used * @param carrierCode the carrier selection code to be used
* @return the formatted phone number in national format for dialing using the carrier as * @return the formatted phone number in national format for dialing using the carrier as
* specified in the {@code carrierCode}
* specified in the {@code carrierCode}
*/ */
public String formatNationalNumberWithCarrierCode(PhoneNumber number, String carrierCode) { public String formatNationalNumberWithCarrierCode(PhoneNumber number, String carrierCode) {
int countryCallingCode = number.getCountryCode(); int countryCallingCode = number.getCountryCode();
@ -1279,8 +1279,8 @@ public class PhoneNumberUtil {
boolean isValidNumber = (numberType != PhoneNumberType.UNKNOWN); boolean isValidNumber = (numberType != PhoneNumberType.UNKNOWN);
if (regionCallingFrom.equals(regionCode)) { if (regionCallingFrom.equals(regionCode)) {
boolean isFixedLineOrMobile = boolean isFixedLineOrMobile =
(numberType == PhoneNumberType.FIXED_LINE) || (numberType == PhoneNumberType.MOBILE) ||
(numberType == PhoneNumberType.FIXED_LINE_OR_MOBILE);
(numberType == PhoneNumberType.FIXED_LINE) || (numberType == PhoneNumberType.MOBILE)
|| (numberType == PhoneNumberType.FIXED_LINE_OR_MOBILE);
// Carrier codes may be needed in some countries. We handle this here. // Carrier codes may be needed in some countries. We handle this here.
if (regionCode.equals("CO") && numberType == PhoneNumberType.FIXED_LINE) { if (regionCode.equals("CO") && numberType == PhoneNumberType.FIXED_LINE) {
formattedNumber = formattedNumber =
@ -1305,8 +1305,8 @@ public class PhoneNumberUtil {
// internationally, since that always works, except for numbers which might potentially be // internationally, since that always works, except for numbers which might potentially be
// short numbers, which are always dialled in national format. // short numbers, which are always dialled in national format.
PhoneMetadata regionMetadata = getMetadataForRegion(regionCallingFrom); PhoneMetadata regionMetadata = getMetadataForRegion(regionCallingFrom);
if (canBeInternationallyDialled(numberNoExt) &&
!isShorterThanPossibleNormalNumber(regionMetadata,
if (canBeInternationallyDialled(numberNoExt)
&& !isShorterThanPossibleNormalNumber(regionMetadata,
getNationalSignificantNumber(numberNoExt))) { getNationalSignificantNumber(numberNoExt))) {
formattedNumber = format(numberNoExt, PhoneNumberFormat.INTERNATIONAL); formattedNumber = format(numberNoExt, PhoneNumberFormat.INTERNATIONAL);
} else { } else {
@ -1316,18 +1316,18 @@ public class PhoneNumberUtil {
// For non-geographical countries, and Mexican and Chilean fixed line and mobile numbers, we // For non-geographical countries, and Mexican and Chilean fixed line and mobile numbers, we
// output international format for numbers that can be dialed internationally as that always // output international format for numbers that can be dialed internationally as that always
// works. // works.
if ((regionCode.equals(REGION_CODE_FOR_NON_GEO_ENTITY) ||
// MX fixed line and mobile numbers should always be formatted in international format,
// even when dialed within MX. For national format to work, a carrier code needs to be
// used, and the correct carrier code depends on if the caller and callee are from the
// same local area. It is trickier to get that to work correctly than using
// international format, which is tested to work fine on all carriers.
// CL fixed line numbers need the national prefix when dialing in the national format,
// but don't have it when used for display. The reverse is true for mobile numbers.
// As a result, we output them in the international format to make it work.
((regionCode.equals("MX") || regionCode.equals("CL")) &&
isFixedLineOrMobile)) &&
canBeInternationallyDialled(numberNoExt)) {
if ((regionCode.equals(REGION_CODE_FOR_NON_GEO_ENTITY)
// MX fixed line and mobile numbers should always be formatted in international format,
// even when dialed within MX. For national format to work, a carrier code needs to be
// used, and the correct carrier code depends on if the caller and callee are from the
// same local area. It is trickier to get that to work correctly than using
// international format, which is tested to work fine on all carriers.
// CL fixed line numbers need the national prefix when dialing in the national format,
// but don't have it when used for display. The reverse is true for mobile numbers. As
// a result, we output them in the international format to make it work.
|| ((regionCode.equals("MX") || regionCode.equals("CL"))
&& isFixedLineOrMobile))
&& canBeInternationallyDialled(numberNoExt)) {
formattedNumber = format(numberNoExt, PhoneNumberFormat.INTERNATIONAL); formattedNumber = format(numberNoExt, PhoneNumberFormat.INTERNATIONAL);
} else { } else {
formattedNumber = format(numberNoExt, PhoneNumberFormat.NATIONAL); formattedNumber = format(numberNoExt, PhoneNumberFormat.NATIONAL);
@ -1357,8 +1357,8 @@ public class PhoneNumberUtil {
* is used. For regions which have multiple international prefixes, the number in its * is used. For regions which have multiple international prefixes, the number in its
* INTERNATIONAL format will be returned instead. * INTERNATIONAL format will be returned instead.
* *
* @param number the phone number to be formatted
* @param regionCallingFrom the region where the call is being placed
* @param number the phone number to be formatted
* @param regionCallingFrom the region where the call is being placed
* @return the formatted phone number * @return the formatted phone number
*/ */
public String formatOutOfCountryCallingNumber(PhoneNumber number, public String formatOutOfCountryCallingNumber(PhoneNumber number,
@ -1441,8 +1441,8 @@ public class PhoneNumberUtil {
* @return the formatted phone number in its original number format * @return the formatted phone number in its original number format
*/ */
public String formatInOriginalFormat(PhoneNumber number, String regionCallingFrom) { public String formatInOriginalFormat(PhoneNumber number, String regionCallingFrom) {
if (number.hasRawInput() &&
(hasUnexpectedItalianLeadingZero(number) || !hasFormattingPatternForNumber(number))) {
if (number.hasRawInput()
&& (hasUnexpectedItalianLeadingZero(number) || !hasFormattingPatternForNumber(number))) {
// We check if we have the formatting pattern because without that, we might format the number // We check if we have the formatting pattern because without that, we might format the number
// as a group without national prefix. // as a group without national prefix.
return number.getRawInput(); return number.getRawInput();
@ -1635,8 +1635,8 @@ public class PhoneNumberUtil {
if (isNANPACountry(regionCallingFrom)) { if (isNANPACountry(regionCallingFrom)) {
return countryCode + " " + rawInput; return countryCode + " " + rawInput;
} }
} else if (metadataForRegionCallingFrom != null &&
countryCode == getCountryCodeForValidRegion(regionCallingFrom)) {
} else if (metadataForRegionCallingFrom != null
&& countryCode == getCountryCodeForValidRegion(regionCallingFrom)) {
NumberFormat formattingPattern = NumberFormat formattingPattern =
chooseFormattingPatternForNumber(metadataForRegionCallingFrom.numberFormats(), chooseFormattingPatternForNumber(metadataForRegionCallingFrom.numberFormats(),
nationalNumber); nationalNumber);
@ -1794,9 +1794,9 @@ public class PhoneNumberUtil {
Matcher m = Matcher m =
regexCache.getPatternForRegex(formattingPattern.getPattern()).matcher(nationalNumber); regexCache.getPatternForRegex(formattingPattern.getPattern()).matcher(nationalNumber);
String formattedNationalNumber = ""; String formattedNationalNumber = "";
if (numberFormat == PhoneNumberFormat.NATIONAL &&
carrierCode != null && carrierCode.length() > 0 &&
formattingPattern.getDomesticCarrierCodeFormattingRule().length() > 0) {
if (numberFormat == PhoneNumberFormat.NATIONAL
&& carrierCode != null && carrierCode.length() > 0
&& formattingPattern.getDomesticCarrierCodeFormattingRule().length() > 0) {
// Replace the $CC in the formatting rule with the desired carrier code. // Replace the $CC in the formatting rule with the desired carrier code.
String carrierCodeFormattingRule = formattingPattern.getDomesticCarrierCodeFormattingRule(); String carrierCodeFormattingRule = formattingPattern.getDomesticCarrierCodeFormattingRule();
carrierCodeFormattingRule = carrierCodeFormattingRule =
@ -1809,9 +1809,9 @@ public class PhoneNumberUtil {
} else { } else {
// Use the national prefix formatting rule instead. // Use the national prefix formatting rule instead.
String nationalPrefixFormattingRule = formattingPattern.getNationalPrefixFormattingRule(); String nationalPrefixFormattingRule = formattingPattern.getNationalPrefixFormattingRule();
if (numberFormat == PhoneNumberFormat.NATIONAL &&
nationalPrefixFormattingRule != null &&
nationalPrefixFormattingRule.length() > 0) {
if (numberFormat == PhoneNumberFormat.NATIONAL
&& nationalPrefixFormattingRule != null
&& nationalPrefixFormattingRule.length() > 0) {
Matcher firstGroupMatcher = FIRST_GROUP_PATTERN.matcher(numberFormatRule); Matcher firstGroupMatcher = FIRST_GROUP_PATTERN.matcher(numberFormatRule);
formattedNationalNumber = formattedNationalNumber =
m.replaceAll(firstGroupMatcher.replaceFirst(nationalPrefixFormattingRule)); m.replaceAll(firstGroupMatcher.replaceFirst(nationalPrefixFormattingRule));
@ -2088,8 +2088,8 @@ public class PhoneNumberUtil {
} }
// Otherwise, test to see if the number is mobile. Only do this if certain that the patterns for // Otherwise, test to see if the number is mobile. Only do this if certain that the patterns for
// mobile and fixed line aren't the same. // mobile and fixed line aren't the same.
if (!metadata.isSameMobileAndFixedLinePattern() &&
isNumberMatchingDesc(nationalNumber, metadata.getMobile())) {
if (!metadata.isSameMobileAndFixedLinePattern()
&& isNumberMatchingDesc(nationalNumber, metadata.getMobile())) {
return PhoneNumberType.MOBILE; return PhoneNumberType.MOBILE;
} }
return PhoneNumberType.UNKNOWN; return PhoneNumberType.UNKNOWN;
@ -2124,15 +2124,15 @@ public class PhoneNumberUtil {
Matcher nationalNumberPatternMatcher = Matcher nationalNumberPatternMatcher =
regexCache.getPatternForRegex(numberDesc.getNationalNumberPattern()) regexCache.getPatternForRegex(numberDesc.getNationalNumberPattern())
.matcher(nationalNumber); .matcher(nationalNumber);
return isNumberPossibleForDesc(nationalNumber, numberDesc) &&
nationalNumberPatternMatcher.matches();
return isNumberPossibleForDesc(nationalNumber, numberDesc)
&& nationalNumberPatternMatcher.matches();
} }
/** /**
* Tests whether a phone number matches a valid pattern. Note this doesn't verify the number * Tests whether a phone number matches a valid pattern. Note this doesn't verify the number
* is actually in use, which is impossible to tell by just looking at a number itself. * is actually in use, which is impossible to tell by just looking at a number itself.
* *
* @param number the phone number that we want to validate
* @param number the phone number that we want to validate
* @return a boolean that indicates whether the number is of a valid pattern * @return a boolean that indicates whether the number is of a valid pattern
*/ */
public boolean isValidNumber(PhoneNumber number) { public boolean isValidNumber(PhoneNumber number) {
@ -2152,16 +2152,16 @@ public class PhoneNumberUtil {
* the region "GB" (United Kingdom), since it has its own region code, "IM", which may be * the region "GB" (United Kingdom), since it has its own region code, "IM", which may be
* undesirable. * undesirable.
* *
* @param number the phone number that we want to validate
* @param regionCode the region that we want to validate the phone number for
* @param number the phone number that we want to validate
* @param regionCode the region that we want to validate the phone number for
* @return a boolean that indicates whether the number is of a valid pattern * @return a boolean that indicates whether the number is of a valid pattern
*/ */
public boolean isValidNumberForRegion(PhoneNumber number, String regionCode) { public boolean isValidNumberForRegion(PhoneNumber number, String regionCode) {
int countryCode = number.getCountryCode(); int countryCode = number.getCountryCode();
PhoneMetadata metadata = getMetadataForRegionOrCallingCode(countryCode, regionCode); PhoneMetadata metadata = getMetadataForRegionOrCallingCode(countryCode, regionCode);
if ((metadata == null) ||
(!REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCode) &&
countryCode != getCountryCodeForValidRegion(regionCode))) {
if ((metadata == null)
|| (!REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCode)
&& countryCode != getCountryCodeForValidRegion(regionCode))) {
// Either the region code was invalid, or the country calling code for this number does not // Either the region code was invalid, or the country calling code for this number does not
// match that of the region code. // match that of the region code.
return false; return false;
@ -2460,8 +2460,8 @@ public class PhoneNumberUtil {
* Attempts to extract a valid number from a phone number that is too long to be valid, and resets * Attempts to extract a valid number from a phone number that is too long to be valid, and resets
* the PhoneNumber object passed in to that valid version. If no valid number could be extracted, * the PhoneNumber object passed in to that valid version. If no valid number could be extracted,
* the PhoneNumber object passed in will not be modified. * the PhoneNumber object passed in will not be modified.
* @param number a PhoneNumber object which contains a number that is too long to be valid.
* @return true if a valid phone number can be successfully extracted.
* @param number a PhoneNumber object which contains a number that is too long to be valid
* @return true if a valid phone number can be successfully extracted
*/ */
public boolean truncateTooLongNumber(PhoneNumber number) { public boolean truncateTooLongNumber(PhoneNumber number) {
if (isValidNumber(number)) { if (isValidNumber(number)) {
@ -2473,8 +2473,8 @@ public class PhoneNumberUtil {
do { do {
nationalNumber /= 10; nationalNumber /= 10;
numberCopy.setNationalNumber(nationalNumber); numberCopy.setNationalNumber(nationalNumber);
if (isPossibleNumberWithReason(numberCopy) == ValidationResult.TOO_SHORT ||
nationalNumber == 0) {
if (isPossibleNumberWithReason(numberCopy) == ValidationResult.TOO_SHORT
|| nationalNumber == 0) {
return false; return false;
} }
} while (!isValidNumber(numberCopy)); } while (!isValidNumber(numberCopy));
@ -2601,10 +2601,10 @@ public class PhoneNumberUtil {
// If the number was not valid before but is valid now, or if it was too long before, we // If the number was not valid before but is valid now, or if it was too long before, we
// consider the number with the country calling code stripped to be a better result and // consider the number with the country calling code stripped to be a better result and
// keep that instead. // keep that instead.
if ((!validNumberPattern.matcher(fullNumber).matches() &&
validNumberPattern.matcher(potentialNationalNumber).matches()) ||
testNumberLengthAgainstPattern(possibleNumberPattern, fullNumber.toString())
== ValidationResult.TOO_LONG) {
if ((!validNumberPattern.matcher(fullNumber).matches()
&& validNumberPattern.matcher(potentialNationalNumber).matches())
|| testNumberLengthAgainstPattern(possibleNumberPattern, fullNumber.toString())
== ValidationResult.TOO_LONG) {
nationalNumber.append(potentialNationalNumber); nationalNumber.append(potentialNationalNumber);
if (keepRawInput) { if (keepRawInput) {
phoneNumber.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN); phoneNumber.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN);
@ -2647,12 +2647,12 @@ public class PhoneNumberUtil {
* the resulting number, and indicates if an international prefix was present. * the resulting number, and indicates if an international prefix was present.
* *
* @param number the non-normalized telephone number that we wish to strip any international * @param number the non-normalized telephone number that we wish to strip any international
* dialing prefix from.
* dialing prefix from
* @param possibleIddPrefix the international direct dialing prefix from the region we * @param possibleIddPrefix the international direct dialing prefix from the region we
* think this number may be dialed in * think this number may be dialed in
* @return the corresponding CountryCodeSource if an international dialing prefix could be * @return the corresponding CountryCodeSource if an international dialing prefix could be
* removed from the number, otherwise CountryCodeSource.FROM_DEFAULT_COUNTRY if the number did * removed from the number, otherwise CountryCodeSource.FROM_DEFAULT_COUNTRY if the number did
* not seem to be in international format.
* not seem to be in international format
*/ */
// @VisibleForTesting // @VisibleForTesting
CountryCodeSource maybeStripInternationalPrefixAndNormalize( CountryCodeSource maybeStripInternationalPrefixAndNormalize(
@ -2684,7 +2684,7 @@ public class PhoneNumberUtil {
* dialing prefix from * dialing prefix from
* @param metadata the metadata for the region that we think this number is from * @param metadata the metadata for the region that we think this number is from
* @param carrierCode a place to insert the carrier code if one is extracted * @param carrierCode a place to insert the carrier code if one is extracted
* @return true if a national prefix or carrier code (or both) could be extracted.
* @return true if a national prefix or carrier code (or both) could be extracted
*/ */
// @VisibleForTesting // @VisibleForTesting
boolean maybeStripNationalPrefixAndCarrierCode( boolean maybeStripNationalPrefixAndCarrierCode(
@ -2707,11 +2707,11 @@ public class PhoneNumberUtil {
// remove the national prefix. // remove the national prefix.
int numOfGroups = prefixMatcher.groupCount(); int numOfGroups = prefixMatcher.groupCount();
String transformRule = metadata.getNationalPrefixTransformRule(); String transformRule = metadata.getNationalPrefixTransformRule();
if (transformRule == null || transformRule.length() == 0 ||
prefixMatcher.group(numOfGroups) == null) {
if (transformRule == null || transformRule.length() == 0
|| prefixMatcher.group(numOfGroups) == null) {
// If the original number was viable, and the resultant number is not, we return. // If the original number was viable, and the resultant number is not, we return.
if (isViableOriginalNumber &&
!nationalNumberRule.matcher(number.substring(prefixMatcher.end())).matches()) {
if (isViableOriginalNumber
&& !nationalNumberRule.matcher(number.substring(prefixMatcher.end())).matches()) {
return false; return false;
} }
if (carrierCode != null && numOfGroups > 0 && prefixMatcher.group(numOfGroups) != null) { if (carrierCode != null && numOfGroups > 0 && prefixMatcher.group(numOfGroups) != null) {
@ -2724,8 +2724,8 @@ public class PhoneNumberUtil {
// the string buffer and making the transformation on the copy first. // the string buffer and making the transformation on the copy first.
StringBuilder transformedNumber = new StringBuilder(number); StringBuilder transformedNumber = new StringBuilder(number);
transformedNumber.replace(0, numberLength, prefixMatcher.replaceFirst(transformRule)); transformedNumber.replace(0, numberLength, prefixMatcher.replaceFirst(transformRule));
if (isViableOriginalNumber &&
!nationalNumberRule.matcher(transformedNumber.toString()).matches()) {
if (isViableOriginalNumber
&& !nationalNumberRule.matcher(transformedNumber.toString()).matches()) {
return false; return false;
} }
if (carrierCode != null && numOfGroups > 1) { if (carrierCode != null && numOfGroups > 1) {
@ -2743,7 +2743,7 @@ public class PhoneNumberUtil {
* usually indicated with extn, ext, x or similar) from the end of the number, and returns it. * usually indicated with extn, ext, x or similar) from the end of the number, and returns it.
* *
* @param number the non-normalized telephone number that we wish to strip the extension from * @param number the non-normalized telephone number that we wish to strip the extension from
* @return the phone extension
* @return the phone extension
*/ */
// @VisibleForTesting // @VisibleForTesting
String maybeStripExtension(StringBuilder number) { String maybeStripExtension(StringBuilder number) {
@ -2773,8 +2773,8 @@ public class PhoneNumberUtil {
private boolean checkRegionForParsing(String numberToParse, String defaultRegion) { private boolean checkRegionForParsing(String numberToParse, String defaultRegion) {
if (!isValidRegionCode(defaultRegion)) { if (!isValidRegionCode(defaultRegion)) {
// If the number is null or empty, we can't infer the region. // If the number is null or empty, we can't infer the region.
if ((numberToParse == null) || (numberToParse.length() == 0) ||
!PLUS_CHARS_PATTERN.matcher(numberToParse).lookingAt()) {
if ((numberToParse == null) || (numberToParse.length() == 0)
|| !PLUS_CHARS_PATTERN.matcher(numberToParse).lookingAt()) {
return false; return false;
} }
} }
@ -2795,20 +2795,18 @@ public class PhoneNumberUtil {
* is actually a valid number for a particular region is not performed. This can be done * is actually a valid number for a particular region is not performed. This can be done
* separately with {@link #isValidNumber}. * separately with {@link #isValidNumber}.
* *
* @param numberToParse number that we are attempting to parse. This can contain formatting
* such as +, ( and -, as well as a phone number extension. It can also
* be provided in RFC3966 format.
* @param defaultRegion region that we are expecting the number to be from. This is only used
* if the number being parsed is not written in international format.
* The country_code for the number in this case would be stored as that
* of the default region supplied. If the number is guaranteed to
* start with a '+' followed by the country calling code, then
* "ZZ" or null can be supplied.
* @return a phone number proto buffer filled with the parsed number
* @param numberToParse number that we are attempting to parse. This can contain formatting such
* as +, ( and -, as well as a phone number extension. It can also be provided in RFC3966
* format.
* @param defaultRegion region that we are expecting the number to be from. This is only used if
* the number being parsed is not written in international format. The country_code for the
* number in this case would be stored as that of the default region supplied. If the number
* is guaranteed to start with a '+' followed by the country calling code, then RegionCode.ZZ
* or null can be supplied.
* @return a phone number proto buffer filled with the parsed number
* @throws NumberParseException if the string is not considered to be a viable phone number (e.g. * @throws NumberParseException if the string is not considered to be a viable phone number (e.g.
* too few or too many digits) or if no default region was supplied
* and the number is not in international format (does not start
* with +)
* too few or too many digits) or if no default region was supplied and the number is not in
* international format (does not start with +)
*/ */
public PhoneNumber parse(String numberToParse, String defaultRegion) public PhoneNumber parse(String numberToParse, String defaultRegion)
throws NumberParseException { throws NumberParseException {
@ -2831,15 +2829,14 @@ public class PhoneNumberUtil {
* in that it always populates the raw_input field of the protocol buffer with numberToParse as * in that it always populates the raw_input field of the protocol buffer with numberToParse as
* well as the country_code_source field. * well as the country_code_source field.
* *
* @param numberToParse number that we are attempting to parse. This can contain formatting
* such as +, ( and -, as well as a phone number extension.
* @param defaultRegion region that we are expecting the number to be from. This is only used
* if the number being parsed is not written in international format.
* The country calling code for the number in this case would be stored
* as that of the default region supplied.
* @return a phone number proto buffer filled with the parsed number
* @param numberToParse number that we are attempting to parse. This can contain formatting such
* as +, ( and -, as well as a phone number extension.
* @param defaultRegion region that we are expecting the number to be from. This is only used if
* the number being parsed is not written in international format. The country calling code
* for the number in this case would be stored as that of the default region supplied.
* @return a phone number proto buffer filled with the parsed number
* @throws NumberParseException if the string is not considered to be a viable phone number or if * @throws NumberParseException if the string is not considered to be a viable phone number or if
* no default region was supplied
* no default region was supplied
*/ */
public PhoneNumber parseAndKeepRawInput(String numberToParse, String defaultRegion) public PhoneNumber parseAndKeepRawInput(String numberToParse, String defaultRegion)
throws NumberParseException { throws NumberParseException {
@ -2863,12 +2860,11 @@ public class PhoneNumberUtil {
* is a shortcut for {@link #findNumbers(CharSequence, String, Leniency, long) * is a shortcut for {@link #findNumbers(CharSequence, String, Leniency, long)
* getMatcher(text, defaultRegion, Leniency.VALID, Long.MAX_VALUE)}. * getMatcher(text, defaultRegion, Leniency.VALID, Long.MAX_VALUE)}.
* *
* @param text the text to search for phone numbers, null for no text
* @param defaultRegion region that we are expecting the number to be from. This is only used
* if the number being parsed is not written in international format. The
* country_code for the number in this case would be stored as that of
* the default region supplied. May be null if only international
* numbers are expected.
* @param text the text to search for phone numbers, null for no text
* @param defaultRegion region that we are expecting the number to be from. This is only used if
* the number being parsed is not written in international format. The country_code for the
* number in this case would be stored as that of the default region supplied. May be null if
* only international numbers are expected.
*/ */
public Iterable<PhoneNumberMatch> findNumbers(CharSequence text, String defaultRegion) { public Iterable<PhoneNumberMatch> findNumbers(CharSequence text, String defaultRegion) {
return findNumbers(text, defaultRegion, Leniency.VALID, Long.MAX_VALUE); return findNumbers(text, defaultRegion, Leniency.VALID, Long.MAX_VALUE);
@ -2877,16 +2873,15 @@ public class PhoneNumberUtil {
/** /**
* Returns an iterable over all {@link PhoneNumberMatch PhoneNumberMatches} in {@code text}. * Returns an iterable over all {@link PhoneNumberMatch PhoneNumberMatches} in {@code text}.
* *
* @param text the text to search for phone numbers, null for no text
* @param defaultRegion region that we are expecting the number to be from. This is only used
* if the number being parsed is not written in international format. The
* country_code for the number in this case would be stored as that of
* the default region supplied. May be null if only international
* numbers are expected.
* @param leniency the leniency to use when evaluating candidate phone numbers
* @param maxTries the maximum number of invalid numbers to try before giving up on the
* text. This is to cover degenerate cases where the text has a lot of
* false positives in it. Must be {@code >= 0}.
* @param text the text to search for phone numbers, null for no text
* @param defaultRegion region that we are expecting the number to be from. This is only used if
* the number being parsed is not written in international format. The country_code for the
* number in this case would be stored as that of the default region supplied. May be null if
* only international numbers are expected.
* @param leniency the leniency to use when evaluating candidate phone numbers
* @param maxTries the maximum number of invalid numbers to try before giving up on the text.
* This is to cover degenerate cases where the text has a lot of false positives in it. Must
* be {@code >= 0}.
*/ */
public Iterable<PhoneNumberMatch> findNumbers( public Iterable<PhoneNumberMatch> findNumbers(
final CharSequence text, final String defaultRegion, final Leniency leniency, final CharSequence text, final String defaultRegion, final Leniency leniency,
@ -2910,8 +2905,8 @@ public class PhoneNumberUtil {
int numberOfLeadingZeros = 1; int numberOfLeadingZeros = 1;
// Note that if the national number is all "0"s, the last "0" is not counted as a leading // Note that if the national number is all "0"s, the last "0" is not counted as a leading
// zero. // zero.
while (numberOfLeadingZeros < nationalNumber.length() - 1 &&
nationalNumber.charAt(numberOfLeadingZeros) == '0') {
while (numberOfLeadingZeros < nationalNumber.length() - 1
&& nationalNumber.charAt(numberOfLeadingZeros) == '0') {
numberOfLeadingZeros++; numberOfLeadingZeros++;
} }
if (numberOfLeadingZeros != 1) { if (numberOfLeadingZeros != 1) {
@ -2975,8 +2970,8 @@ public class PhoneNumberUtil {
normalizedNationalNumber, keepRawInput, phoneNumber); normalizedNationalNumber, keepRawInput, phoneNumber);
} catch (NumberParseException e) { } catch (NumberParseException e) {
Matcher matcher = PLUS_CHARS_PATTERN.matcher(nationalNumber.toString()); Matcher matcher = PLUS_CHARS_PATTERN.matcher(nationalNumber.toString());
if (e.getErrorType() == NumberParseException.ErrorType.INVALID_COUNTRY_CODE &&
matcher.lookingAt()) {
if (e.getErrorType() == NumberParseException.ErrorType.INVALID_COUNTRY_CODE
&& matcher.lookingAt()) {
// Strip the plus-char, and try again. // Strip the plus-char, and try again.
countryCode = maybeExtractCountryCode(nationalNumber.substring(matcher.end()), countryCode = maybeExtractCountryCode(nationalNumber.substring(matcher.end()),
regionMetadata, normalizedNationalNumber, regionMetadata, normalizedNationalNumber,
@ -3016,8 +3011,8 @@ public class PhoneNumberUtil {
StringBuilder potentialNationalNumber = new StringBuilder(normalizedNationalNumber); StringBuilder potentialNationalNumber = new StringBuilder(normalizedNationalNumber);
maybeStripNationalPrefixAndCarrierCode(potentialNationalNumber, regionMetadata, carrierCode); maybeStripNationalPrefixAndCarrierCode(potentialNationalNumber, regionMetadata, carrierCode);
// We require that the NSN remaining after stripping the national prefix and carrier code be // We require that the NSN remaining after stripping the national prefix and carrier code be
// of a possible length for the region. Otherwise, we don't do the stripping, since the
// original number could be a valid short number.
// long enough to be a possible length for the region. Otherwise, we don't do the stripping,
// since the original number could be a valid short number.
if (!isShorterThanPossibleNormalNumber(regionMetadata, potentialNationalNumber.toString())) { if (!isShorterThanPossibleNormalNumber(regionMetadata, potentialNationalNumber.toString())) {
normalizedNationalNumber = potentialNationalNumber; normalizedNationalNumber = potentialNationalNumber;
if (keepRawInput) { if (keepRawInput) {
@ -3065,8 +3060,8 @@ public class PhoneNumberUtil {
// handle the case when "tel:" is missing, as we have seen in some of the phone number inputs. // handle the case when "tel:" is missing, as we have seen in some of the phone number inputs.
// In that case, we append everything from the beginning. // In that case, we append everything from the beginning.
int indexOfRfc3966Prefix = numberToParse.indexOf(RFC3966_PREFIX); int indexOfRfc3966Prefix = numberToParse.indexOf(RFC3966_PREFIX);
int indexOfNationalNumber = (indexOfRfc3966Prefix >= 0) ?
indexOfRfc3966Prefix + RFC3966_PREFIX.length() : 0;
int indexOfNationalNumber = (indexOfRfc3966Prefix >= 0)
? indexOfRfc3966Prefix + RFC3966_PREFIX.length() : 0;
nationalNumber.append(numberToParse.substring(indexOfNationalNumber, indexOfPhoneContext)); nationalNumber.append(numberToParse.substring(indexOfNationalNumber, indexOfPhoneContext));
} else { } else {
// Extract a possible number from the string passed in (this strips leading characters that // Extract a possible number from the string passed in (this strips leading characters that
@ -3120,17 +3115,17 @@ public class PhoneNumberUtil {
secondNumber.clearRawInput(); secondNumber.clearRawInput();
secondNumber.clearCountryCodeSource(); secondNumber.clearCountryCodeSource();
secondNumber.clearPreferredDomesticCarrierCode(); secondNumber.clearPreferredDomesticCarrierCode();
if (firstNumber.hasExtension() &&
firstNumber.getExtension().length() == 0) {
firstNumber.clearExtension();
if (firstNumber.hasExtension()
&& firstNumber.getExtension().length() == 0) {
firstNumber.clearExtension();
} }
if (secondNumber.hasExtension() &&
secondNumber.getExtension().length() == 0) {
secondNumber.clearExtension();
if (secondNumber.hasExtension()
&& secondNumber.getExtension().length() == 0) {
secondNumber.clearExtension();
} }
// Early exit if both had extensions and these are different. // Early exit if both had extensions and these are different.
if (firstNumber.hasExtension() && secondNumber.hasExtension() &&
!firstNumber.getExtension().equals(secondNumber.getExtension())) {
if (firstNumber.hasExtension() && secondNumber.hasExtension()
&& !firstNumber.getExtension().equals(secondNumber.getExtension())) {
return MatchType.NO_MATCH; return MatchType.NO_MATCH;
} }
int firstNumberCountryCode = firstNumber.getCountryCode(); int firstNumberCountryCode = firstNumber.getCountryCode();
@ -3139,8 +3134,8 @@ public class PhoneNumberUtil {
if (firstNumberCountryCode != 0 && secondNumberCountryCode != 0) { if (firstNumberCountryCode != 0 && secondNumberCountryCode != 0) {
if (firstNumber.exactlySameAs(secondNumber)) { if (firstNumber.exactlySameAs(secondNumber)) {
return MatchType.EXACT_MATCH; return MatchType.EXACT_MATCH;
} else if (firstNumberCountryCode == secondNumberCountryCode &&
isNationalNumberSuffixOfTheOther(firstNumber, secondNumber)) {
} else if (firstNumberCountryCode == secondNumberCountryCode
&& isNationalNumberSuffixOfTheOther(firstNumber, secondNumber)) {
// A SHORT_NSN_MATCH occurs if there is a difference because of the presence or absence of // A SHORT_NSN_MATCH occurs if there is a difference because of the presence or absence of
// an 'Italian leading zero', the presence or absence of an extension, or one NSN being a // an 'Italian leading zero', the presence or absence of an extension, or one NSN being a
// shorter variant of the other. // shorter variant of the other.
@ -3168,8 +3163,8 @@ public class PhoneNumberUtil {
String firstNumberNationalNumber = String.valueOf(firstNumber.getNationalNumber()); String firstNumberNationalNumber = String.valueOf(firstNumber.getNationalNumber());
String secondNumberNationalNumber = String.valueOf(secondNumber.getNationalNumber()); String secondNumberNationalNumber = String.valueOf(secondNumber.getNationalNumber());
// Note that endsWith returns true if the numbers are equal. // Note that endsWith returns true if the numbers are equal.
return firstNumberNationalNumber.endsWith(secondNumberNationalNumber) ||
secondNumberNationalNumber.endsWith(firstNumberNationalNumber);
return firstNumberNationalNumber.endsWith(secondNumberNationalNumber)
|| secondNumberNationalNumber.endsWith(firstNumberNationalNumber);
} }
/** /**
@ -3215,7 +3210,7 @@ public class PhoneNumberUtil {
* Takes two phone numbers and compares them for equality. This is a convenience wrapper for * Takes two phone numbers and compares them for equality. This is a convenience wrapper for
* {@link #isNumberMatch(PhoneNumber, PhoneNumber)}. No default region is known. * {@link #isNumberMatch(PhoneNumber, PhoneNumber)}. No default region is known.
* *
* @param firstNumber first number to compare in proto buffer format.
* @param firstNumber first number to compare in proto buffer format
* @param secondNumber second number to compare. Can contain formatting, and can have country * @param secondNumber second number to compare. Can contain formatting, and can have country
* calling code specified with + at the start. * calling code specified with + at the start.
* @return NOT_A_NUMBER, NO_MATCH, SHORT_NSN_MATCH, NSN_MATCH, EXACT_MATCH. See * @return NOT_A_NUMBER, NO_MATCH, SHORT_NSN_MATCH, NSN_MATCH, EXACT_MATCH. See
@ -3283,7 +3278,7 @@ public class PhoneNumberUtil {
* invalid, unknown or regions that don't support mobile number portability. * invalid, unknown or regions that don't support mobile number portability.
* *
* @param regionCode the region for which we want to know whether it supports mobile number * @param regionCode the region for which we want to know whether it supports mobile number
* portability or not.
* portability or not
*/ */
public boolean isMobileNumberPortableRegion(String regionCode) { public boolean isMobileNumberPortableRegion(String regionCode) {
PhoneMetadata metadata = getMetadataForRegion(regionCode); PhoneMetadata metadata = getMetadataForRegion(regionCode);


+ 2
- 2
java/libphonenumber/src/com/google/i18n/phonenumbers/RegexCache.java View File

@ -41,7 +41,7 @@ public class RegexCache {
return pattern; return pattern;
} }
// This method is used for testing.
// @VisibleForTesting
boolean containsRegex(String regex) { boolean containsRegex(String regex) {
return cache.containsKey(regex); return cache.containsKey(regex);
} }
@ -54,6 +54,7 @@ public class RegexCache {
@SuppressWarnings("serial") @SuppressWarnings("serial")
public LRUCache(int size) { public LRUCache(int size) {
this.size = size; this.size = size;
// Using access-order instead of insertion-order.
map = new LinkedHashMap<K, V>(size * 4 / 3 + 1, 0.75f, true) { map = new LinkedHashMap<K, V>(size * 4 / 3 + 1, 0.75f, true) {
@Override @Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
@ -75,4 +76,3 @@ public class RegexCache {
} }
} }
} }

+ 1
- 1
java/libphonenumber/src/com/google/i18n/phonenumbers/ShortNumberInfo.java View File

@ -61,7 +61,7 @@ public class ShortNumberInfo {
TOLL_FREE, TOLL_FREE,
STANDARD_RATE, STANDARD_RATE,
PREMIUM_RATE, PREMIUM_RATE,
UNKNOWN_COST
UNKNOWN_COST;
} }
/** Returns the singleton instance of the ShortNumberInfo. */ /** Returns the singleton instance of the ShortNumberInfo. */


+ 19
- 19
java/libphonenumber/test/com/google/i18n/phonenumbers/ExampleNumbersTest.java View File

@ -34,7 +34,7 @@ import java.util.logging.Logger;
* example number exists for a particular type, the test still passes. * example number exists for a particular type, the test still passes.
*/ */
public class ExampleNumbersTest extends TestCase { public class ExampleNumbersTest extends TestCase {
private static final Logger LOGGER = Logger.getLogger(ExampleNumbersTest.class.getName());
private static final Logger logger = Logger.getLogger(ExampleNumbersTest.class.getName());
private PhoneNumberUtil phoneNumberUtil = private PhoneNumberUtil phoneNumberUtil =
PhoneNumberUtil.createInstance(PhoneNumberUtil.DEFAULT_METADATA_LOADER); PhoneNumberUtil.createInstance(PhoneNumberUtil.DEFAULT_METADATA_LOADER);
private ShortNumberInfo shortNumberInfo = ShortNumberInfo.getInstance(); private ShortNumberInfo shortNumberInfo = ShortNumberInfo.getInstance();
@ -54,18 +54,18 @@ public class ExampleNumbersTest extends TestCase {
if (exampleNumber != null) { if (exampleNumber != null) {
if (!phoneNumberUtil.isValidNumber(exampleNumber)) { if (!phoneNumberUtil.isValidNumber(exampleNumber)) {
invalidCases.add(exampleNumber); invalidCases.add(exampleNumber);
LOGGER.log(Level.SEVERE, "Failed validation for " + exampleNumber.toString());
logger.log(Level.SEVERE, "Failed validation for " + exampleNumber.toString());
} else { } else {
// We know the number is valid, now we check the type. // We know the number is valid, now we check the type.
PhoneNumberType exampleNumberType = phoneNumberUtil.getNumberType(exampleNumber); PhoneNumberType exampleNumberType = phoneNumberUtil.getNumberType(exampleNumber);
if (!possibleExpectedTypes.contains(exampleNumberType)) { if (!possibleExpectedTypes.contains(exampleNumberType)) {
wrongTypeCases.add(exampleNumber); wrongTypeCases.add(exampleNumber);
LOGGER.log(Level.SEVERE, "Wrong type for " +
exampleNumber.toString() +
": got " + exampleNumberType);
LOGGER.log(Level.WARNING, "Expected types: ");
logger.log(Level.SEVERE, "Wrong type for "
+ exampleNumber.toString()
+ ": got " + exampleNumberType);
logger.log(Level.WARNING, "Expected types: ");
for (PhoneNumberType type : possibleExpectedTypes) { for (PhoneNumberType type : possibleExpectedTypes) {
LOGGER.log(Level.WARNING, type.toString());
logger.log(Level.WARNING, type.toString());
} }
} }
} }
@ -148,12 +148,12 @@ public class ExampleNumbersTest extends TestCase {
exampleNumber = phoneNumberUtil.parse(desc.getExampleNumber(), regionCode); exampleNumber = phoneNumberUtil.parse(desc.getExampleNumber(), regionCode);
} }
} catch (NumberParseException e) { } catch (NumberParseException e) {
LOGGER.log(Level.SEVERE, e.toString());
logger.log(Level.SEVERE, e.toString());
} }
if (exampleNumber != null && phoneNumberUtil.canBeInternationallyDialled(exampleNumber)) { if (exampleNumber != null && phoneNumberUtil.canBeInternationallyDialled(exampleNumber)) {
wrongTypeCases.add(exampleNumber); wrongTypeCases.add(exampleNumber);
LOGGER.log(Level.SEVERE, "Number " + exampleNumber.toString()
+ " should not be internationally diallable");
logger.log(Level.SEVERE, "Number " + exampleNumber.toString()
+ " should not be internationally diallable");
} }
} }
assertEquals(0, wrongTypeCases.size()); assertEquals(0, wrongTypeCases.size());
@ -166,7 +166,7 @@ public class ExampleNumbersTest extends TestCase {
assertNotNull("No example phone number for calling code " + callingCode, exampleNumber); assertNotNull("No example phone number for calling code " + callingCode, exampleNumber);
if (!phoneNumberUtil.isValidNumber(exampleNumber)) { if (!phoneNumberUtil.isValidNumber(exampleNumber)) {
invalidCases.add(exampleNumber); invalidCases.add(exampleNumber);
LOGGER.log(Level.SEVERE, "Failed validation for " + exampleNumber.toString());
logger.log(Level.SEVERE, "Failed validation for " + exampleNumber.toString());
} }
} }
assertEquals(0, invalidCases.size()); assertEquals(0, invalidCases.size());
@ -199,15 +199,15 @@ public class ExampleNumbersTest extends TestCase {
String exampleShortNumber = shortNumberInfo.getExampleShortNumber(regionCode); String exampleShortNumber = shortNumberInfo.getExampleShortNumber(regionCode);
if (!shortNumberInfo.isValidShortNumberForRegion( if (!shortNumberInfo.isValidShortNumberForRegion(
phoneNumberUtil.parse(exampleShortNumber, regionCode), regionCode)) { phoneNumberUtil.parse(exampleShortNumber, regionCode), regionCode)) {
String invalidStringCase = "region_code: " + regionCode + ", national_number: " +
exampleShortNumber;
String invalidStringCase = "region_code: " + regionCode + ", national_number: "
+ exampleShortNumber;
invalidStringCases.add(invalidStringCase); invalidStringCases.add(invalidStringCase);
LOGGER.log(Level.SEVERE, "Failed validation for string " + invalidStringCase);
logger.log(Level.SEVERE, "Failed validation for string " + invalidStringCase);
} }
PhoneNumber phoneNumber = phoneNumberUtil.parse(exampleShortNumber, regionCode); PhoneNumber phoneNumber = phoneNumberUtil.parse(exampleShortNumber, regionCode);
if (!shortNumberInfo.isValidShortNumber(phoneNumber)) { if (!shortNumberInfo.isValidShortNumber(phoneNumber)) {
invalidCases.add(phoneNumber); invalidCases.add(phoneNumber);
LOGGER.log(Level.SEVERE, "Failed validation for " + phoneNumber.toString());
logger.log(Level.SEVERE, "Failed validation for " + phoneNumber.toString());
} }
for (ShortNumberInfo.ShortNumberCost cost : ShortNumberInfo.ShortNumberCost.values()) { for (ShortNumberInfo.ShortNumberCost cost : ShortNumberInfo.ShortNumberCost.values()) {
@ -218,7 +218,7 @@ public class ExampleNumbersTest extends TestCase {
shortNumberInfo.getExpectedCostForRegion(phoneNumber, regionCode); shortNumberInfo.getExpectedCostForRegion(phoneNumber, regionCode);
if (cost != exampleShortNumberCost) { if (cost != exampleShortNumberCost) {
wrongTypeCases.add(phoneNumber); wrongTypeCases.add(phoneNumber);
LOGGER.log(Level.SEVERE, "Wrong cost for " + phoneNumber.toString()
logger.log(Level.SEVERE, "Wrong cost for " + phoneNumber.toString()
+ ": got " + exampleShortNumberCost + ": got " + exampleShortNumberCost
+ ", expected: " + cost); + ", expected: " + cost);
} }
@ -241,11 +241,11 @@ public class ExampleNumbersTest extends TestCase {
if (!shortNumberInfo.isPossibleShortNumberForRegion(phoneNumber, regionCode) if (!shortNumberInfo.isPossibleShortNumberForRegion(phoneNumber, regionCode)
|| !shortNumberInfo.isEmergencyNumber(exampleNumber, regionCode)) { || !shortNumberInfo.isEmergencyNumber(exampleNumber, regionCode)) {
wrongTypeCounter++; wrongTypeCounter++;
LOGGER.log(Level.SEVERE, "Emergency example number test failed for " + regionCode);
logger.log(Level.SEVERE, "Emergency example number test failed for " + regionCode);
} else if (shortNumberInfo.getExpectedCostForRegion(phoneNumber, regionCode) } else if (shortNumberInfo.getExpectedCostForRegion(phoneNumber, regionCode)
!= ShortNumberInfo.ShortNumberCost.TOLL_FREE) { != ShortNumberInfo.ShortNumberCost.TOLL_FREE) {
wrongTypeCounter++; wrongTypeCounter++;
LOGGER.log(Level.WARNING, "Emergency example number not toll free for " + regionCode);
logger.log(Level.WARNING, "Emergency example number not toll free for " + regionCode);
} }
} }
} }
@ -264,7 +264,7 @@ public class ExampleNumbersTest extends TestCase {
if (!shortNumberInfo.isPossibleShortNumberForRegion(carrierSpecificNumber, regionCode) if (!shortNumberInfo.isPossibleShortNumberForRegion(carrierSpecificNumber, regionCode)
|| !shortNumberInfo.isCarrierSpecific(carrierSpecificNumber)) { || !shortNumberInfo.isCarrierSpecific(carrierSpecificNumber)) {
wrongTagCounter++; wrongTagCounter++;
LOGGER.log(Level.SEVERE, "Carrier-specific test failed for " + regionCode);
logger.log(Level.SEVERE, "Carrier-specific test failed for " + regionCode);
} }
} }
// TODO: Test other tags here. // TODO: Test other tags here.


+ 4
- 4
java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberMatcherTest.java View File

@ -119,8 +119,8 @@ public class PhoneNumberMatcherTest extends TestMetadataTestCase {
// Using a full-width plus sign. // Using a full-width plus sign.
doTestFindInContext("\uFF0B1 (650) 333-6000", RegionCode.SG); doTestFindInContext("\uFF0B1 (650) 333-6000", RegionCode.SG);
// The whole number, including punctuation, is here represented in full-width form. // The whole number, including punctuation, is here represented in full-width form.
doTestFindInContext("\uFF0B\uFF11\u3000\uFF08\uFF16\uFF15\uFF10\uFF09" +
"\u3000\uFF13\uFF13\uFF13\uFF0D\uFF16\uFF10\uFF10\uFF10",
doTestFindInContext("\uFF0B\uFF11\u3000\uFF08\uFF16\uFF15\uFF10\uFF09"
+ "\u3000\uFF13\uFF13\uFF13\uFF0D\uFF16\uFF10\uFF10\uFF10",
RegionCode.SG); RegionCode.SG);
} }
@ -611,8 +611,8 @@ public class PhoneNumberMatcherTest extends TestMetadataTestCase {
} else { } else {
if (!test.rawString.equals(match.rawString())) { if (!test.rawString.equals(match.rawString())) {
wrongMatchFoundCount++; wrongMatchFoundCount++;
System.err.println("Found wrong match in test " + test.toString() +
". Found " + match.rawString());
System.err.println("Found wrong match in test " + test.toString()
+ ". Found " + match.rawString());
} }
} }
} }


+ 8
- 1
java/pending_code_changes.txt View File

@ -1 +1,8 @@
Build changes:
- OSGi support added to Manifest information when building jar (#1300)
- BuildMetadataJsonFromXml changed to output possible lengths for JS build
Code changes:
- Formatting, naming (LOGGER -> logger) and comment tweaks to follow style
guide
- Removal of unneeded canBeGeocoded method in the
PhoneNumberToTimeZonesMapper.java, using phoneNumberUtil instead

+ 4
- 5
tools/java/common/src/com/google/i18n/phonenumbers/BuildMetadataFromXml.java View File

@ -45,7 +45,7 @@ import org.w3c.dom.NodeList;
* @author Shaopeng Jia * @author Shaopeng Jia
*/ */
public class BuildMetadataFromXml { public class BuildMetadataFromXml {
private static final Logger LOGGER = Logger.getLogger(BuildMetadataFromXml.class.getName());
private static final Logger logger = Logger.getLogger(BuildMetadataFromXml.class.getName());
// String constants used to fetch the XML nodes and attributes. // String constants used to fetch the XML nodes and attributes.
private static final String CARRIER_CODE_FORMATTING_RULE = "carrierCodeFormattingRule"; private static final String CARRIER_CODE_FORMATTING_RULE = "carrierCodeFormattingRule";
@ -166,7 +166,7 @@ public class BuildMetadataFromXml {
// of a bug. If one wants to make something optional, we prefer ? to using an empty group. // of a bug. If one wants to make something optional, we prefer ? to using an empty group.
int errorIndex = compressedRegex.indexOf("|)"); int errorIndex = compressedRegex.indexOf("|)");
if (errorIndex >= 0) { if (errorIndex >= 0) {
LOGGER.log(Level.SEVERE, "Error with original regex: " + regex
logger.log(Level.SEVERE, "Error with original regex: " + regex
+ "\n| should not be followed directly by ) in phone number regular expressions."); + "\n| should not be followed directly by ) in phone number regular expressions.");
throw new PatternSyntaxException("| followed by )", compressedRegex, errorIndex); throw new PatternSyntaxException("| followed by )", compressedRegex, errorIndex);
} }
@ -244,7 +244,7 @@ public class BuildMetadataFromXml {
boolean hasExplicitIntlFormatDefined = false; boolean hasExplicitIntlFormatDefined = false;
if (intlFormatPattern.getLength() > 1) { if (intlFormatPattern.getLength() > 1) {
LOGGER.log(Level.SEVERE,
logger.log(Level.SEVERE,
"A maximum of one intlFormat pattern for a numberFormat element should be defined."); "A maximum of one intlFormat pattern for a numberFormat element should be defined.");
String countryId = metadata.getId().length() > 0 ? metadata.getId() String countryId = metadata.getId().length() > 0 ? metadata.getId()
: Integer.toString(metadata.getCountryCode()); : Integer.toString(metadata.getCountryCode());
@ -282,7 +282,7 @@ public class BuildMetadataFromXml {
NodeList formatPattern = numberFormatElement.getElementsByTagName(FORMAT); NodeList formatPattern = numberFormatElement.getElementsByTagName(FORMAT);
int numFormatPatterns = formatPattern.getLength(); int numFormatPatterns = formatPattern.getLength();
if (numFormatPatterns != 1) { if (numFormatPatterns != 1) {
LOGGER.log(Level.SEVERE, "One format pattern for a numberFormat element should be defined.");
logger.log(Level.SEVERE, "One format pattern for a numberFormat element should be defined.");
String countryId = metadata.getId().length() > 0 ? metadata.getId() String countryId = metadata.getId().length() > 0 ? metadata.getId()
: Integer.toString(metadata.getCountryCode()); : Integer.toString(metadata.getCountryCode());
throw new RuntimeException("Invalid number of format patterns (" + numFormatPatterns throw new RuntimeException("Invalid number of format patterns (" + numFormatPatterns
@ -450,7 +450,6 @@ public class BuildMetadataFromXml {
if (parentDesc != null) { if (parentDesc != null) {
numberDesc.mergeFrom(parentDesc); numberDesc.mergeFrom(parentDesc);
} }
if (phoneNumberDescList.getLength() > 0) { if (phoneNumberDescList.getLength() > 0) {
if (phoneNumberDescList.getLength() > 1) { if (phoneNumberDescList.getLength() > 1) {
throw new RuntimeException( throw new RuntimeException(


+ 16
- 16
tools/java/java-build/src/com/google/i18n/phonenumbers/BuildMetadataJsonFromXml.java View File

@ -51,26 +51,26 @@ public class BuildMetadataJsonFromXml extends Command {
"BuildMetadataJsonFromXml PhoneNumberMetadata.xml metadatalite.js true\n"; "BuildMetadataJsonFromXml PhoneNumberMetadata.xml metadatalite.js true\n";
private static final String FILE_OVERVIEW = private static final String FILE_OVERVIEW =
"/**\n" +
" * @fileoverview Generated metadata for file\n" +
" * %s\n" +
" * @author Nikolaos Trogkanis\n" +
" */\n\n";
"/**\n"
+ " * @fileoverview Generated metadata for file\n"
+ " * %s\n"
+ " * @author Nikolaos Trogkanis\n"
+ " */\n\n";
private static final String COUNTRY_CODE_TO_REGION_CODE_MAP_COMMENT = private static final String COUNTRY_CODE_TO_REGION_CODE_MAP_COMMENT =
"/**\n" +
" * A mapping from a country calling code to the region codes which denote the\n" +
" * region represented by that country calling code. In the case of multiple\n" +
" * countries sharing a calling code, such as the NANPA regions, the one\n" +
" * indicated with \"isMainCountryForCode\" in the metadata should be first.\n" +
" * @type {!Object.<number, Array.<string>>}\n" +
" */\n";
"/**\n"
+ " * A mapping from a country calling code to the region codes which denote the\n"
+ " * region represented by that country calling code. In the case of multiple\n"
+ " * countries sharing a calling code, such as the NANPA regions, the one\n"
+ " * indicated with \"isMainCountryForCode\" in the metadata should be first.\n"
+ " * @type {!Object.<number, Array.<string>>}\n"
+ " */\n";
private static final String COUNTRY_TO_METADATA_COMMENT = private static final String COUNTRY_TO_METADATA_COMMENT =
"/**\n" +
" * A mapping from a region code to the PhoneMetadata for that region.\n" +
" * @type {!Object.<string, Array>}\n" +
" */\n";
"/**\n"
+ " * A mapping from a region code to the PhoneMetadata for that region.\n"
+ " * @type {!Object.<string, Array>}\n"
+ " */\n";
private static final int COPYRIGHT_YEAR = 2010; private static final int COPYRIGHT_YEAR = 2010;


+ 2
- 2
tools/java/java-build/src/com/google/i18n/phonenumbers/buildtools/AbstractPhonePrefixDataIOHandler.java View File

@ -27,7 +27,7 @@ import java.util.logging.Logger;
* the phone prefix data to them. * the phone prefix data to them.
*/ */
public abstract class AbstractPhonePrefixDataIOHandler { public abstract class AbstractPhonePrefixDataIOHandler {
private static final Logger LOGGER = Logger.getLogger(
private static final Logger logger = Logger.getLogger(
AbstractPhonePrefixDataIOHandler.class.getName()); AbstractPhonePrefixDataIOHandler.class.getName());
/** /**
* Adds the provided file to a global output that can be for example a JAR. * Adds the provided file to a global output that can be for example a JAR.
@ -56,7 +56,7 @@ public abstract class AbstractPhonePrefixDataIOHandler {
try { try {
closeable.close(); closeable.close();
} catch (IOException e) { } catch (IOException e) {
LOGGER.log(Level.WARNING, e.getMessage());
logger.log(Level.WARNING, e.getMessage());
} }
} }
} }

+ 9
- 9
tools/java/java-build/src/com/google/i18n/phonenumbers/buildtools/GeneratePhonePrefixData.java View File

@ -68,13 +68,13 @@ public class GeneratePhonePrefixData {
// The IO Handler used to output the generated binary files. // The IO Handler used to output the generated binary files.
private final AbstractPhonePrefixDataIOHandler ioHandler; private final AbstractPhonePrefixDataIOHandler ioHandler;
private static final Logger LOGGER = Logger.getLogger(GeneratePhonePrefixData.class.getName());
private static final Logger logger = Logger.getLogger(GeneratePhonePrefixData.class.getName());
public GeneratePhonePrefixData(File inputPath, AbstractPhonePrefixDataIOHandler ioHandler) public GeneratePhonePrefixData(File inputPath, AbstractPhonePrefixDataIOHandler ioHandler)
throws IOException { throws IOException {
if (!inputPath.isDirectory()) { if (!inputPath.isDirectory()) {
throw new IOException("The provided input path does not exist: " +
inputPath.getAbsolutePath());
throw new IOException("The provided input path does not exist: "
+ inputPath.getAbsolutePath());
} }
this.inputPath = inputPath; this.inputPath = inputPath;
this.ioHandler = ioHandler; this.ioHandler = ioHandler;
@ -138,7 +138,7 @@ public class GeneratePhonePrefixData {
/** /**
* Reads the mappings contained in the provided input stream pointing to a text file. * Reads the mappings contained in the provided input stream pointing to a text file.
* *
* @return a map containing the mappings that were read.
* @return a map containing the mappings that were read
*/ */
// @VisibleForTesting // @VisibleForTesting
static SortedMap<Integer, String> readMappingsFromTextFile(InputStream input) static SortedMap<Integer, String> readMappingsFromTextFile(InputStream input)
@ -384,8 +384,8 @@ public class GeneratePhonePrefixData {
private void makeDataFallbackToEnglish(File inputTextFile, SortedMap<Integer, String> mappings) private void makeDataFallbackToEnglish(File inputTextFile, SortedMap<Integer, String> mappings)
throws IOException { throws IOException {
File englishTextFile = new File(getEnglishDataPath(inputTextFile.getAbsolutePath())); File englishTextFile = new File(getEnglishDataPath(inputTextFile.getAbsolutePath()));
if (inputTextFile.getAbsolutePath().equals(englishTextFile.getAbsolutePath()) ||
!englishTextFile.exists()) {
if (inputTextFile.getAbsolutePath().equals(englishTextFile.getAbsolutePath())
|| !englishTextFile.exists()) {
return; return;
} }
int countryCode = getCountryCodeFromTextFileName(inputTextFile.getName()); int countryCode = getCountryCodeFromTextFileName(inputTextFile.getName());
@ -457,11 +457,11 @@ public class GeneratePhonePrefixData {
} }
} }
} catch (RuntimeException e) { } catch (RuntimeException e) {
LOGGER.log(Level.SEVERE,
logger.log(Level.SEVERE,
"Error processing file " + inputOutputMapping.getKey().getAbsolutePath()); "Error processing file " + inputOutputMapping.getKey().getAbsolutePath());
throw e; throw e;
} catch (IOException e) { } catch (IOException e) {
LOGGER.log(Level.SEVERE, e.getMessage());
logger.log(Level.SEVERE, e.getMessage());
} finally { } finally {
ioHandler.closeFile(fileInputStream); ioHandler.closeFile(fileInputStream);
ioHandler.closeFile(fileOutputStream); ioHandler.closeFile(fileOutputStream);
@ -478,6 +478,6 @@ public class GeneratePhonePrefixData {
ioHandler.closeFile(fileOutputStream); ioHandler.closeFile(fileOutputStream);
ioHandler.close(); ioHandler.close();
} }
LOGGER.log(Level.INFO, "Phone prefix data successfully generated.");
logger.log(Level.INFO, "Phone prefix data successfully generated.");
} }
} }

+ 5
- 4
tools/java/java-build/src/com/google/i18n/phonenumbers/buildtools/GeneratePhonePrefixDataEntryPoint.java View File

@ -29,7 +29,7 @@ import java.util.logging.Logger;
* @author Philippe Liard * @author Philippe Liard
*/ */
public class GeneratePhonePrefixDataEntryPoint extends Command { public class GeneratePhonePrefixDataEntryPoint extends Command {
private static final Logger LOGGER = Logger.getLogger(GeneratePhonePrefixData.class.getName());
private static final Logger logger = Logger.getLogger(GeneratePhonePrefixData.class.getName());
@Override @Override
public String getCommandName() { public String getCommandName() {
@ -41,8 +41,9 @@ public class GeneratePhonePrefixDataEntryPoint extends Command {
String[] args = getArgs(); String[] args = getArgs();
if (args.length != 3) { if (args.length != 3) {
LOGGER.log(Level.SEVERE,
"usage: GeneratePhonePrefixData /path/to/input/directory /path/to/output/directory");
logger.log(Level.SEVERE,
"usage: GeneratePhonePrefixData /path/to/input/directory "
+ "/path/to/output/directory");
return false; return false;
} }
try { try {
@ -50,7 +51,7 @@ public class GeneratePhonePrefixDataEntryPoint extends Command {
new GeneratePhonePrefixData(new File(args[1]), new PhonePrefixDataIOHandler(new File(args[2]))); new GeneratePhonePrefixData(new File(args[1]), new PhonePrefixDataIOHandler(new File(args[2])));
generatePhonePrefixData.run(); generatePhonePrefixData.run();
} catch (IOException e) { } catch (IOException e) {
LOGGER.log(Level.SEVERE, e.getMessage());
logger.log(Level.SEVERE, e.getMessage());
return false; return false;
} }
return true; return true;


+ 6
- 8
tools/java/java-build/src/com/google/i18n/phonenumbers/buildtools/GenerateTimeZonesMapData.java View File

@ -35,10 +35,8 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
/** /**
* A utility that generates the binary serialization of the prefix/time zones mappings from
* a human-readable text file.
*
* @author Walter Erquinigo
* A utility that generates the binary serialization of the prefix/time zones mappings from a
* human-readable text file.
*/ */
public class GenerateTimeZonesMapData { public class GenerateTimeZonesMapData {
private final File inputTextFile; private final File inputTextFile;
@ -46,7 +44,7 @@ public class GenerateTimeZonesMapData {
// The IO Handler used to output the generated binary file. // The IO Handler used to output the generated binary file.
private final AbstractPhonePrefixDataIOHandler ioHandler; private final AbstractPhonePrefixDataIOHandler ioHandler;
private static final Logger LOGGER = Logger.getLogger(GenerateTimeZonesMapData.class.getName());
private static final Logger logger = Logger.getLogger(GenerateTimeZonesMapData.class.getName());
public GenerateTimeZonesMapData(File inputTextFile, AbstractPhonePrefixDataIOHandler ioHandler) public GenerateTimeZonesMapData(File inputTextFile, AbstractPhonePrefixDataIOHandler ioHandler)
throws IOException { throws IOException {
@ -128,16 +126,16 @@ public class GenerateTimeZonesMapData {
ioHandler.closeFile(fileOutputStream); ioHandler.closeFile(fileOutputStream);
} }
} catch (RuntimeException e) { } catch (RuntimeException e) {
LOGGER.log(Level.SEVERE,
logger.log(Level.SEVERE,
"Error processing file " + inputTextFile.getAbsolutePath()); "Error processing file " + inputTextFile.getAbsolutePath());
throw e; throw e;
} catch (IOException e) { } catch (IOException e) {
LOGGER.log(Level.SEVERE, e.getMessage());
logger.log(Level.SEVERE, e.getMessage());
} finally { } finally {
ioHandler.closeFile(fileInputStream); ioHandler.closeFile(fileInputStream);
ioHandler.closeFile(fileOutputStream); ioHandler.closeFile(fileOutputStream);
ioHandler.close(); ioHandler.close();
} }
LOGGER.log(Level.INFO, "Time zone data successfully generated.");
logger.log(Level.INFO, "Time zone data successfully generated.");
} }
} }

+ 5
- 5
tools/java/java-build/src/com/google/i18n/phonenumbers/buildtools/GenerateTimeZonesMapDataEntryPoint.java View File

@ -30,7 +30,7 @@ import java.util.logging.Logger;
* @author Philippe Liard * @author Philippe Liard
*/ */
public class GenerateTimeZonesMapDataEntryPoint extends Command { public class GenerateTimeZonesMapDataEntryPoint extends Command {
private static final Logger LOGGER = Logger.getLogger(GenerateTimeZonesMapData.class.getName());
private static final Logger logger = Logger.getLogger(GenerateTimeZonesMapData.class.getName());
@Override @Override
public String getCommandName() { public String getCommandName() {
@ -42,9 +42,9 @@ public class GenerateTimeZonesMapDataEntryPoint extends Command {
String[] args = getArgs(); String[] args = getArgs();
if (args.length != 3) { if (args.length != 3) {
LOGGER.log(Level.SEVERE,
"usage: GenerateTimeZonesMapData /path/to/input/text_file " +
"/path/to/output/directory");
logger.log(Level.SEVERE,
"usage: GenerateTimeZonesMapData /path/to/input/text_file "
+ "/path/to/output/directory");
return false; return false;
} }
try { try {
@ -52,7 +52,7 @@ public class GenerateTimeZonesMapDataEntryPoint extends Command {
new File(args[1]), new PhonePrefixDataIOHandler(new File(args[2]))); new File(args[1]), new PhonePrefixDataIOHandler(new File(args[2])));
generateTimeZonesMapData.run(); generateTimeZonesMapData.run();
} catch (IOException e) { } catch (IOException e) {
LOGGER.log(Level.SEVERE, e.getMessage());
logger.log(Level.SEVERE, e.getMessage());
return false; return false;
} }
return true; return true;


Loading…
Cancel
Save