Browse Source

Replacing some public APIs that take phone numbers as strings with CharSequence. Removed two private methods that were unused (leftover from a previous commit). (#1847)

pull/790/merge
lararennie 9 years ago
committed by Keghani Kouzoujian
parent
commit
7e6feaeeea
5 changed files with 115 additions and 142 deletions
  1. +10
    -10
      java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberMatcher.java
  2. +81
    -113
      java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java
  3. +6
    -7
      java/libphonenumber/src/com/google/i18n/phonenumbers/ShortNumberInfo.java
  4. +8
    -12
      java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java
  5. +10
    -0
      pending_code_changes.txt

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

@ -326,15 +326,14 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
} }
// Try to come up with a valid match given the entire candidate. // Try to come up with a valid match given the entire candidate.
String rawString = candidate.toString();
PhoneNumberMatch match = parseAndVerify(rawString, offset);
PhoneNumberMatch match = parseAndVerify(candidate, offset);
if (match != null) { if (match != null) {
return match; return match;
} }
// If that failed, try to find an "inner match" - there might be a phone number within this // If that failed, try to find an "inner match" - there might be a phone number within this
// candidate. // candidate.
return extractInnerMatch(rawString, offset);
return extractInnerMatch(candidate, offset);
} }
/** /**
@ -345,7 +344,7 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
* @param offset the current offset of {@code candidate} within {@link #text} * @param offset the current offset of {@code candidate} within {@link #text}
* @return the match found, null if none can be found * @return the match found, null if none can be found
*/ */
private PhoneNumberMatch extractInnerMatch(String candidate, int offset) {
private PhoneNumberMatch extractInnerMatch(CharSequence candidate, int offset) {
for (Pattern possibleInnerMatch : INNER_MATCHES) { for (Pattern possibleInnerMatch : INNER_MATCHES) {
Matcher groupMatcher = possibleInnerMatch.matcher(candidate); Matcher groupMatcher = possibleInnerMatch.matcher(candidate);
boolean isFirstMatch = true; boolean isFirstMatch = true;
@ -354,8 +353,8 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
// We should handle any group before this one too. // We should handle any group before this one too.
CharSequence group = trimAfterFirstMatch( CharSequence group = trimAfterFirstMatch(
PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN, PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN,
candidate.substring(0, groupMatcher.start()));
PhoneNumberMatch match = parseAndVerify(group.toString(), offset);
candidate.subSequence(0, groupMatcher.start()));
PhoneNumberMatch match = parseAndVerify(group, offset);
if (match != null) { if (match != null) {
return match; return match;
} }
@ -364,7 +363,7 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
} }
CharSequence group = trimAfterFirstMatch( CharSequence group = trimAfterFirstMatch(
PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN, groupMatcher.group(1)); PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN, groupMatcher.group(1));
PhoneNumberMatch match = parseAndVerify(group.toString(), offset + groupMatcher.start(1));
PhoneNumberMatch match = parseAndVerify(group, offset + groupMatcher.start(1));
if (match != null) { if (match != null) {
return match; return match;
} }
@ -383,7 +382,7 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
* @param offset the offset of {@code candidate} within {@link #text} * @param offset the offset of {@code candidate} within {@link #text}
* @return the parsed and validated phone number match, or null * @return the parsed and validated phone number match, or null
*/ */
private PhoneNumberMatch parseAndVerify(String candidate, int offset) {
private PhoneNumberMatch parseAndVerify(CharSequence candidate, int offset) {
try { try {
// Check the candidate doesn't contain any formatting which would indicate that it really // Check the candidate doesn't contain any formatting which would indicate that it really
// isn't a phone number. // isn't a phone number.
@ -440,7 +439,7 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
number.clearCountryCodeSource(); number.clearCountryCodeSource();
number.clearRawInput(); number.clearRawInput();
number.clearPreferredDomesticCarrierCode(); number.clearPreferredDomesticCarrierCode();
return new PhoneNumberMatch(offset, candidate, number);
return new PhoneNumberMatch(offset, candidate.toString(), number);
} }
} catch (NumberParseException e) { } catch (NumberParseException e) {
// ignore and continue // ignore and continue
@ -572,7 +571,8 @@ final class PhoneNumberMatcher implements Iterator<PhoneNumberMatch> {
} }
static boolean checkNumberGroupingIsValid( static boolean checkNumberGroupingIsValid(
PhoneNumber number, String candidate, PhoneNumberUtil util, NumberGroupingChecker checker) {
PhoneNumber number, CharSequence candidate, PhoneNumberUtil util,
NumberGroupingChecker checker) {
// TODO: Evaluate how this works for other locales (testing has been limited to NANPA regions) // TODO: Evaluate how this works for other locales (testing has been limited to NANPA regions)
// and optimise if necessary. // and optimise if necessary.
StringBuilder normalizedCandidate = StringBuilder normalizedCandidate =


+ 81
- 113
java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java View File

@ -363,9 +363,11 @@ public class PhoneNumberUtil {
// correctly. Therefore, we use \d, so that the first group actually used in the pattern will be // correctly. Therefore, we use \d, so that the first group actually used in the pattern will be
// matched. // matched.
private static final Pattern FIRST_GROUP_PATTERN = Pattern.compile("(\\$\\d)"); private static final Pattern FIRST_GROUP_PATTERN = Pattern.compile("(\\$\\d)");
private static final Pattern NP_PATTERN = Pattern.compile("\\$NP");
private static final Pattern FG_PATTERN = Pattern.compile("\\$FG");
private static final Pattern CC_PATTERN = Pattern.compile("\\$CC");
// Constants used in the formatting rules to represent the national prefix, first group and
// carrier code respectively.
private static final String NP_STRING = "$NP";
private static final String FG_STRING = "$FG";
private static final String CC_STRING = "$CC";
// A pattern that is used to determine if the national prefix formatting rule has the first group // A pattern that is used to determine if the national prefix formatting rule has the first group
// only, i.e., does not start with the national prefix. Note that the pattern explicitly allows // only, i.e., does not start with the national prefix. Note that the pattern explicitly allows
@ -478,7 +480,7 @@ public class PhoneNumberUtil {
*/ */
POSSIBLE { POSSIBLE {
@Override @Override
boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) {
boolean verify(PhoneNumber number, CharSequence candidate, PhoneNumberUtil util) {
return util.isPossibleNumber(number); return util.isPossibleNumber(number);
} }
}, },
@ -490,9 +492,9 @@ public class PhoneNumberUtil {
*/ */
VALID { VALID {
@Override @Override
boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) {
boolean verify(PhoneNumber number, CharSequence candidate, PhoneNumberUtil util) {
if (!util.isValidNumber(number) if (!util.isValidNumber(number)
|| !PhoneNumberMatcher.containsOnlyValidXChars(number, candidate, util)) {
|| !PhoneNumberMatcher.containsOnlyValidXChars(number, candidate.toString(), util)) {
return false; return false;
} }
return PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util); return PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util);
@ -512,10 +514,11 @@ public class PhoneNumberUtil {
*/ */
STRICT_GROUPING { STRICT_GROUPING {
@Override @Override
boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) {
boolean verify(PhoneNumber number, CharSequence candidate, PhoneNumberUtil util) {
String candidateString = candidate.toString();
if (!util.isValidNumber(number) if (!util.isValidNumber(number)
|| !PhoneNumberMatcher.containsOnlyValidXChars(number, candidate, util)
|| PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)
|| !PhoneNumberMatcher.containsOnlyValidXChars(number, candidateString, util)
|| PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidateString)
|| !PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util)) { || !PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util)) {
return false; return false;
} }
@ -544,10 +547,11 @@ public class PhoneNumberUtil {
*/ */
EXACT_GROUPING { EXACT_GROUPING {
@Override @Override
boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) {
boolean verify(PhoneNumber number, CharSequence candidate, PhoneNumberUtil util) {
String candidateString = candidate.toString();
if (!util.isValidNumber(number) if (!util.isValidNumber(number)
|| !PhoneNumberMatcher.containsOnlyValidXChars(number, candidate, util)
|| PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidate)
|| !PhoneNumberMatcher.containsOnlyValidXChars(number, candidateString, util)
|| PhoneNumberMatcher.containsMoreThanOneSlashInNationalNumber(number, candidateString)
|| !PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util)) { || !PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util)) {
return false; return false;
} }
@ -565,7 +569,7 @@ public class PhoneNumberUtil {
}; };
/** Returns true if {@code number} is a verified number according to this leniency. */ /** Returns true if {@code number} is a verified number according to this leniency. */
abstract boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util);
abstract boolean verify(PhoneNumber number, CharSequence candidate, PhoneNumberUtil util);
} }
// A source of metadata for different regions. // A source of metadata for different regions.
@ -644,20 +648,20 @@ public class PhoneNumberUtil {
* string if no character used to start phone numbers (such as + or any digit) is found in the * string if no character used to start phone numbers (such as + or any digit) is found in the
* number * number
*/ */
static String extractPossibleNumber(String number) {
static CharSequence extractPossibleNumber(CharSequence number) {
Matcher m = VALID_START_CHAR_PATTERN.matcher(number); Matcher m = VALID_START_CHAR_PATTERN.matcher(number);
if (m.find()) { if (m.find()) {
number = number.substring(m.start());
number = number.subSequence(m.start(), number.length());
// Remove trailing non-alpha non-numerical characters. // Remove trailing non-alpha non-numerical characters.
Matcher trailingCharsMatcher = UNWANTED_END_CHAR_PATTERN.matcher(number); Matcher trailingCharsMatcher = UNWANTED_END_CHAR_PATTERN.matcher(number);
if (trailingCharsMatcher.find()) { if (trailingCharsMatcher.find()) {
number = number.substring(0, trailingCharsMatcher.start());
number = number.subSequence(0, trailingCharsMatcher.start());
logger.log(Level.FINER, "Stripped trailing characters: " + number); logger.log(Level.FINER, "Stripped trailing characters: " + number);
} }
// Check for extra numbers at the end. // Check for extra numbers at the end.
Matcher secondNumber = SECOND_NUMBER_START_PATTERN.matcher(number); Matcher secondNumber = SECOND_NUMBER_START_PATTERN.matcher(number);
if (secondNumber.find()) { if (secondNumber.find()) {
number = number.substring(0, secondNumber.start());
number = number.subSequence(0, secondNumber.start());
} }
return number; return number;
} else { } else {
@ -676,7 +680,7 @@ public class PhoneNumberUtil {
* @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(CharSequence number) {
if (number.length() < MIN_LENGTH_FOR_NSN) { if (number.length() < MIN_LENGTH_FOR_NSN) {
return false; return false;
} }
@ -687,38 +691,27 @@ public class PhoneNumberUtil {
/** /**
* Normalizes a string of characters representing a phone number. This performs the following * Normalizes a string of characters representing a phone number. This performs the following
* conversions: * conversions:
* Punctuation is stripped.
* - Punctuation is stripped.
* For ALPHA/VANITY numbers: * For ALPHA/VANITY numbers:
* Letters are converted to their numeric representation on a telephone keypad. The keypad
* used here is the one defined in ITU Recommendation E.161. This is only done if there are
* 3 or more letters in the number, to lessen the risk that such letters are typos.
* - Letters are converted to their numeric representation on a telephone keypad. The keypad
* used here is the one defined in ITU Recommendation E.161. This is only done if there are 3
* or more letters in the number, to lessen the risk that such letters are typos.
* For other numbers: * For other numbers:
* Wide-ascii digits are converted to normal ASCII (European) digits.
* Arabic-Indic numerals are converted to European numerals.
* Spurious alpha characters are stripped.
* - Wide-ascii digits are converted to normal ASCII (European) digits.
* - Arabic-Indic numerals are converted to European numerals.
* - Spurious alpha characters are stripped.
* *
* @param number a string of characters representing a phone number
* @return the normalized string version of the phone number
* @param number a StringBuilder of characters representing a phone number that will be
* normalized in place
*/ */
static String normalize(String number) {
static StringBuilder normalize(StringBuilder number) {
Matcher m = VALID_ALPHA_PHONE_PATTERN.matcher(number); Matcher m = VALID_ALPHA_PHONE_PATTERN.matcher(number);
if (m.matches()) { if (m.matches()) {
return normalizeHelper(number, ALPHA_PHONE_MAPPINGS, true);
number.replace(0, number.length(), normalizeHelper(number, ALPHA_PHONE_MAPPINGS, true));
} else { } else {
return normalizeDigitsOnly(number);
number.replace(0, number.length(), normalizeDigitsOnly(number));
} }
}
/**
* Normalizes a string of characters representing a phone number. This is a wrapper for
* normalize(String number) but does in-place normalization of the StringBuilder provided.
*
* @param number a StringBuilder of characters representing a phone number that will be
* normalized in place
*/
static void normalize(StringBuilder number) {
String normalizedNumber = normalize(number.toString());
number.replace(0, number.length(), normalizedNumber);
return number;
} }
/** /**
@ -728,13 +721,14 @@ public class PhoneNumberUtil {
* @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(CharSequence number) {
return normalizeDigits(number, false /* strip non-digits */).toString(); return normalizeDigits(number, false /* strip non-digits */).toString();
} }
static StringBuilder normalizeDigits(String number, boolean keepNonDigits) {
static StringBuilder normalizeDigits(CharSequence number, boolean keepNonDigits) {
StringBuilder normalizedDigits = new StringBuilder(number.length()); StringBuilder normalizedDigits = new StringBuilder(number.length());
for (char c : number.toCharArray()) {
for (int i = 0; i < number.length(); i++) {
char c = number.charAt(i);
int digit = Character.digit(c, 10); int digit = Character.digit(c, 10);
if (digit != -1) { if (digit != -1) {
normalizedDigits.append(digit); normalizedDigits.append(digit);
@ -752,7 +746,7 @@ public class PhoneNumberUtil {
* @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 normalizeDiallableCharsOnly(String number) {
public static String normalizeDiallableCharsOnly(CharSequence number) {
return normalizeHelper(number, DIALLABLE_CHAR_MAPPINGS, true /* remove non matches */); return normalizeHelper(number, DIALLABLE_CHAR_MAPPINGS, true /* remove non matches */);
} }
@ -760,7 +754,7 @@ public class PhoneNumberUtil {
* Converts all alpha characters in a number to their respective digits on a keypad, but retains * Converts all alpha characters in a number to their respective digits on a keypad, but retains
* existing formatting. * existing formatting.
*/ */
public static String convertAlphaCharactersInNumber(String number) {
public static String convertAlphaCharactersInNumber(CharSequence number) {
return normalizeHelper(number, ALPHA_PHONE_MAPPINGS, false); return normalizeHelper(number, ALPHA_PHONE_MAPPINGS, false);
} }
@ -930,7 +924,7 @@ public class PhoneNumberUtil {
* be stripped from the number. If this is false, they will be left unchanged in the number. * 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(CharSequence number,
Map<Character, Character> normalizationReplacements, Map<Character, Character> normalizationReplacements,
boolean removeNonMatches) { boolean removeNonMatches) {
StringBuilder normalizedNumber = new StringBuilder(number.length()); StringBuilder normalizedNumber = new StringBuilder(number.length());
@ -1267,9 +1261,8 @@ public class PhoneNumberUtil {
if (nationalPrefix.length() > 0) { if (nationalPrefix.length() > 0) {
// Replace $NP with national prefix and $FG with the first group ($1). // Replace $NP with national prefix and $FG with the first group ($1).
nationalPrefixFormattingRule = nationalPrefixFormattingRule =
NP_PATTERN.matcher(nationalPrefixFormattingRule).replaceFirst(nationalPrefix);
nationalPrefixFormattingRule =
FG_PATTERN.matcher(nationalPrefixFormattingRule).replaceFirst("\\$1");
nationalPrefixFormattingRule.replace(NP_STRING, nationalPrefix);
nationalPrefixFormattingRule = nationalPrefixFormattingRule.replace(FG_STRING, "$1");
numFormatCopy.setNationalPrefixFormattingRule(nationalPrefixFormattingRule); numFormatCopy.setNationalPrefixFormattingRule(nationalPrefixFormattingRule);
} else { } else {
// We don't want to have a rule for how to format the national prefix if there isn't one. // We don't want to have a rule for how to format the national prefix if there isn't one.
@ -1295,7 +1288,7 @@ public class PhoneNumberUtil {
* @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, CharSequence carrierCode) {
int countryCallingCode = number.getCountryCode(); int countryCallingCode = number.getCountryCode();
String nationalSignificantNumber = getNationalSignificantNumber(number); String nationalSignificantNumber = getNationalSignificantNumber(number);
if (!hasValidCountryCallingCode(countryCallingCode)) { if (!hasValidCountryCallingCode(countryCallingCode)) {
@ -1343,7 +1336,7 @@ public class PhoneNumberUtil {
* none is found * none is found
*/ */
public String formatNationalNumberWithPreferredCarrierCode(PhoneNumber number, public String formatNationalNumberWithPreferredCarrierCode(PhoneNumber number,
String fallbackCarrierCode) {
CharSequence fallbackCarrierCode) {
return formatNationalNumberWithCarrierCode(number, return formatNationalNumberWithCarrierCode(number,
// Historically, we set this to an empty string when parsing with raw input if none was // Historically, we set this to an empty string when parsing with raw input if none was
// found in the input string. However, this doesn't result in a number we can dial. For this // found in the input string. However, this doesn't result in a number we can dial. For this
@ -1658,14 +1651,6 @@ public class PhoneNumberUtil {
return false; return false;
} }
/**
* Returns true if a number is from a region whose national significant number couldn't contain a
* leading zero, but has the italian_leading_zero field set to true.
*/
private boolean hasUnexpectedItalianLeadingZero(PhoneNumber number) {
return number.isItalianLeadingZero() && !isLeadingZeroPossible(number.getCountryCode());
}
private boolean hasFormattingPatternForNumber(PhoneNumber number) { private boolean hasFormattingPatternForNumber(PhoneNumber number) {
int countryCallingCode = number.getCountryCode(); int countryCallingCode = number.getCountryCode();
String phoneNumberRegion = getRegionCodeForCountryCode(countryCallingCode); String phoneNumberRegion = getRegionCodeForCountryCode(countryCallingCode);
@ -1849,7 +1834,7 @@ public class PhoneNumberUtil {
private String formatNsn(String number, private String formatNsn(String number,
PhoneMetadata metadata, PhoneMetadata metadata,
PhoneNumberFormat numberFormat, PhoneNumberFormat numberFormat,
String carrierCode) {
CharSequence carrierCode) {
List<NumberFormat> intlNumberFormats = metadata.intlNumberFormats(); List<NumberFormat> intlNumberFormats = metadata.intlNumberFormats();
// When the intlNumberFormats exists, we use that to format national number for the // When the intlNumberFormats exists, we use that to format national number for the
// INTERNATIONAL format instead of using the numberDesc.numberFormats. // INTERNATIONAL format instead of using the numberDesc.numberFormats.
@ -1891,7 +1876,7 @@ public class PhoneNumberUtil {
private String formatNsnUsingPattern(String nationalNumber, private String formatNsnUsingPattern(String nationalNumber,
NumberFormat formattingPattern, NumberFormat formattingPattern,
PhoneNumberFormat numberFormat, PhoneNumberFormat numberFormat,
String carrierCode) {
CharSequence carrierCode) {
String numberFormatRule = formattingPattern.getFormat(); String numberFormatRule = formattingPattern.getFormat();
Matcher m = Matcher m =
regexCache.getPatternForRegex(formattingPattern.getPattern()).matcher(nationalNumber); regexCache.getPatternForRegex(formattingPattern.getPattern()).matcher(nationalNumber);
@ -1901,8 +1886,7 @@ public class PhoneNumberUtil {
&& formattingPattern.getDomesticCarrierCodeFormattingRule().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 =
CC_PATTERN.matcher(carrierCodeFormattingRule).replaceFirst(carrierCode);
carrierCodeFormattingRule = carrierCodeFormattingRule.replace(CC_STRING, carrierCode);
// Now replace the $FG in the formatting rule with the first group and the carrier code // Now replace the $FG in the formatting rule with the first group and the carrier code
// combined in the appropriate way. // combined in the appropriate way.
numberFormatRule = FIRST_GROUP_PATTERN.matcher(numberFormatRule) numberFormatRule = FIRST_GROUP_PATTERN.matcher(numberFormatRule)
@ -2427,21 +2411,6 @@ public class PhoneNumberUtil {
return nanpaRegions.contains(regionCode); return nanpaRegions.contains(regionCode);
} }
/**
* Checks whether the country calling code is from a region whose national significant number
* could contain a leading zero. An example of such a region is Italy. Returns false if no
* metadata for the country is found.
*/
boolean isLeadingZeroPossible(int countryCallingCode) {
PhoneMetadata mainMetadataForCallingCode =
getMetadataForRegionOrCallingCode(countryCallingCode,
getRegionCodeForCountryCode(countryCallingCode));
if (mainMetadataForCallingCode == null) {
return false;
}
return mainMetadataForCallingCode.isLeadingZeroPossible();
}
/** /**
* Checks if the number is a valid vanity (alpha) number such as 800 MICROSOFT. A valid vanity * Checks if the number is a valid vanity (alpha) number such as 800 MICROSOFT. A valid vanity
* number will start with at least 3 digits and will have three or more alpha characters. This * number will start with at least 3 digits and will have three or more alpha characters. This
@ -2452,7 +2421,7 @@ public class PhoneNumberUtil {
* @param number the number that needs to be checked * @param number the number that needs to be checked
* @return true if the number is a valid vanity number * @return true if the number is a valid vanity number
*/ */
public boolean isAlphaNumber(String number) {
public boolean isAlphaNumber(CharSequence number) {
if (!isViablePhoneNumber(number)) { if (!isViablePhoneNumber(number)) {
// Number is too short, or doesn't match the basic phone number pattern. // Number is too short, or doesn't match the basic phone number pattern.
return false; return false;
@ -2503,7 +2472,7 @@ public class PhoneNumberUtil {
* number pattern suggests that numbers of length 7 and 10 are possible, and a number in between * number pattern suggests that numbers of length 7 and 10 are possible, and a number in between
* these possible lengths is entered, such as of length 8, this will return TOO_LONG. * these possible lengths is entered, such as of length 8, this will return TOO_LONG.
*/ */
private ValidationResult testNumberLength(String number, PhoneMetadata metadata) {
private ValidationResult testNumberLength(CharSequence number, PhoneMetadata metadata) {
return testNumberLength(number, metadata, PhoneNumberType.UNKNOWN); return testNumberLength(number, metadata, PhoneNumberType.UNKNOWN);
} }
@ -2514,7 +2483,7 @@ public class PhoneNumberUtil {
* entered, such as of length 8, this will return TOO_LONG. * entered, such as of length 8, this will return TOO_LONG.
*/ */
private ValidationResult testNumberLength( private ValidationResult testNumberLength(
String number, PhoneMetadata metadata, PhoneNumberType type) {
CharSequence number, PhoneMetadata metadata, PhoneNumberType type) {
PhoneNumberDesc descForType = getNumberDescByType(metadata, type); PhoneNumberDesc descForType = getNumberDescByType(metadata, type);
// There should always be "possibleLengths" set for every element. This is declared in the XML // There should always be "possibleLengths" set for every element. This is declared in the XML
// schema which is verified by PhoneNumberMetadataSchemaTest. // schema which is verified by PhoneNumberMetadataSchemaTest.
@ -2662,7 +2631,7 @@ public class PhoneNumberUtil {
* <p>This method first parses the number, then invokes {@link #isPossibleNumber(PhoneNumber)} * <p>This method first parses the number, then invokes {@link #isPossibleNumber(PhoneNumber)}
* with the resultant PhoneNumber object. * with the resultant PhoneNumber object.
* *
* @param number the number that needs to be checked, in the form of a string
* @param number the number that needs to be checked
* @param regionDialingFrom the region that we are expecting the number to be dialed from. * @param regionDialingFrom the region that we are expecting the number to be dialed from.
* Note this is different from the region where the number belongs. For example, the number * Note this is different from the region where the number belongs. For example, the number
* +1 650 253 0000 is a number that belongs to US. When written in this form, it can be * +1 650 253 0000 is a number that belongs to US. When written in this form, it can be
@ -2673,7 +2642,7 @@ public class PhoneNumberUtil {
* specific). * specific).
* @return true if the number is possible * @return true if the number is possible
*/ */
public boolean isPossibleNumber(String number, String regionDialingFrom) {
public boolean isPossibleNumber(CharSequence number, String regionDialingFrom) {
try { try {
return isPossibleNumber(parse(number, regionDialingFrom)); return isPossibleNumber(parse(number, regionDialingFrom));
} catch (NumberParseException e) { } catch (NumberParseException e) {
@ -2771,7 +2740,7 @@ public class PhoneNumberUtil {
* @return the country calling code extracted or 0 if none could be extracted * @return the country calling code extracted or 0 if none could be extracted
*/ */
// @VisibleForTesting // @VisibleForTesting
int maybeExtractCountryCode(String number, PhoneMetadata defaultRegionMetadata,
int maybeExtractCountryCode(CharSequence number, PhoneMetadata defaultRegionMetadata,
StringBuilder nationalNumber, boolean keepRawInput, StringBuilder nationalNumber, boolean keepRawInput,
PhoneNumber phoneNumber) PhoneNumber phoneNumber)
throws NumberParseException { throws NumberParseException {
@ -2824,8 +2793,7 @@ public class PhoneNumberUtil {
// keep that instead. // keep that instead.
if ((!matcherApi.matchNationalNumber(fullNumber, generalDesc, false) if ((!matcherApi.matchNationalNumber(fullNumber, generalDesc, false)
&& matcherApi.matchNationalNumber(potentialNationalNumber, generalDesc, false)) && matcherApi.matchNationalNumber(potentialNationalNumber, generalDesc, false))
|| testNumberLength(fullNumber.toString(), defaultRegionMetadata)
== ValidationResult.TOO_LONG) {
|| testNumberLength(fullNumber, defaultRegionMetadata) == 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);
@ -2991,7 +2959,7 @@ public class PhoneNumberUtil {
* parse starts with a + symbol so that we can attempt to infer the region from the number. * parse starts with a + symbol so that we can attempt to infer the region from the number.
* Returns false if it cannot use the region provided and the region cannot be inferred. * Returns false if it cannot use the region provided and the region cannot be inferred.
*/ */
private boolean checkRegionForParsing(String numberToParse, String defaultRegion) {
private boolean checkRegionForParsing(CharSequence 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) if ((numberToParse == null) || (numberToParse.length() == 0)
@ -3035,7 +3003,7 @@ public class PhoneNumberUtil {
* too few or too many digits) or if no default region was supplied and the number is not in * 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 +) * international format (does not start with +)
*/ */
public PhoneNumber parse(String numberToParse, String defaultRegion)
public PhoneNumber parse(CharSequence numberToParse, String defaultRegion)
throws NumberParseException { throws NumberParseException {
PhoneNumber phoneNumber = new PhoneNumber(); PhoneNumber phoneNumber = new PhoneNumber();
parse(numberToParse, defaultRegion, phoneNumber); parse(numberToParse, defaultRegion, phoneNumber);
@ -3043,10 +3011,10 @@ public class PhoneNumberUtil {
} }
/** /**
* Same as {@link #parse(String, String)}, but accepts mutable PhoneNumber as a parameter to
* decrease object creation when invoked many times.
* Same as {@link #parse(CharSequence, String)}, but accepts mutable PhoneNumber as a
* parameter to decrease object creation when invoked many times.
*/ */
public void parse(String numberToParse, String defaultRegion, PhoneNumber phoneNumber)
public void parse(CharSequence numberToParse, String defaultRegion, PhoneNumber phoneNumber)
throws NumberParseException { throws NumberParseException {
parseHelper(numberToParse, defaultRegion, false, true, phoneNumber); parseHelper(numberToParse, defaultRegion, false, true, phoneNumber);
} }
@ -3065,7 +3033,7 @@ public class PhoneNumberUtil {
* @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(CharSequence numberToParse, String defaultRegion)
throws NumberParseException { throws NumberParseException {
PhoneNumber phoneNumber = new PhoneNumber(); PhoneNumber phoneNumber = new PhoneNumber();
parseAndKeepRawInput(numberToParse, defaultRegion, phoneNumber); parseAndKeepRawInput(numberToParse, defaultRegion, phoneNumber);
@ -3073,10 +3041,10 @@ public class PhoneNumberUtil {
} }
/** /**
* Same as{@link #parseAndKeepRawInput(String, String)}, but accepts a mutable PhoneNumber as
* a parameter to decrease object creation when invoked many times.
* Same as{@link #parseAndKeepRawInput(CharSequence, String)}, but accepts a mutable
* PhoneNumber as a parameter to decrease object creation when invoked many times.
*/ */
public void parseAndKeepRawInput(String numberToParse, String defaultRegion,
public void parseAndKeepRawInput(CharSequence numberToParse, String defaultRegion,
PhoneNumber phoneNumber) PhoneNumber phoneNumber)
throws NumberParseException { throws NumberParseException {
parseHelper(numberToParse, defaultRegion, true, true, phoneNumber); parseHelper(numberToParse, defaultRegion, true, true, phoneNumber);
@ -3126,7 +3094,8 @@ public class PhoneNumberUtil {
/** /**
* A helper function to set the values related to leading zeros in a PhoneNumber. * A helper function to set the values related to leading zeros in a PhoneNumber.
*/ */
static void setItalianLeadingZerosForPhoneNumber(String nationalNumber, PhoneNumber phoneNumber) {
static void setItalianLeadingZerosForPhoneNumber(CharSequence nationalNumber,
PhoneNumber phoneNumber) {
if (nationalNumber.length() > 1 && nationalNumber.charAt(0) == '0') { if (nationalNumber.length() > 1 && nationalNumber.charAt(0) == '0') {
phoneNumber.setItalianLeadingZero(true); phoneNumber.setItalianLeadingZero(true);
int numberOfLeadingZeros = 1; int numberOfLeadingZeros = 1;
@ -3151,8 +3120,8 @@ public class PhoneNumberUtil {
* Note if any new field is added to this method that should always be filled in, even when * Note if any new field is added to this method that should always be filled in, even when
* keepRawInput is false, it should also be handled in the copyCoreFieldsOnly() method. * keepRawInput is false, it should also be handled in the copyCoreFieldsOnly() method.
*/ */
private void parseHelper(String numberToParse, String defaultRegion, boolean keepRawInput,
boolean checkRegion, PhoneNumber phoneNumber)
private void parseHelper(CharSequence numberToParse, String defaultRegion,
boolean keepRawInput, boolean checkRegion, PhoneNumber phoneNumber)
throws NumberParseException { throws NumberParseException {
if (numberToParse == null) { if (numberToParse == null) {
throw new NumberParseException(NumberParseException.ErrorType.NOT_A_NUMBER, throw new NumberParseException(NumberParseException.ErrorType.NOT_A_NUMBER,
@ -3163,22 +3132,23 @@ public class PhoneNumberUtil {
} }
StringBuilder nationalNumber = new StringBuilder(); StringBuilder nationalNumber = new StringBuilder();
buildNationalNumberForParsing(numberToParse, nationalNumber);
String numberBeingParsed = numberToParse.toString();
buildNationalNumberForParsing(numberBeingParsed, nationalNumber);
if (!isViablePhoneNumber(nationalNumber.toString())) {
if (!isViablePhoneNumber(nationalNumber)) {
throw new NumberParseException(NumberParseException.ErrorType.NOT_A_NUMBER, throw new NumberParseException(NumberParseException.ErrorType.NOT_A_NUMBER,
"The string supplied did not seem to be a phone number."); "The string supplied did not seem to be a phone number.");
} }
// Check the region supplied is valid, or that the extracted number starts with some sort of + // Check the region supplied is valid, or that the extracted number starts with some sort of +
// sign so the number's region can be determined. // sign so the number's region can be determined.
if (checkRegion && !checkRegionForParsing(nationalNumber.toString(), defaultRegion)) {
if (checkRegion && !checkRegionForParsing(nationalNumber, defaultRegion)) {
throw new NumberParseException(NumberParseException.ErrorType.INVALID_COUNTRY_CODE, throw new NumberParseException(NumberParseException.ErrorType.INVALID_COUNTRY_CODE,
"Missing or invalid default region."); "Missing or invalid default region.");
} }
if (keepRawInput) { if (keepRawInput) {
phoneNumber.setRawInput(numberToParse);
phoneNumber.setRawInput(numberBeingParsed);
} }
// Attempt to parse extension first, since it doesn't require region-specific data and we want // Attempt to parse extension first, since it doesn't require region-specific data and we want
// to have the non-normalised number here. // to have the non-normalised number here.
@ -3196,10 +3166,10 @@ public class PhoneNumberUtil {
// TODO: This method should really just take in the string buffer that has already // TODO: This method should really just take in the string buffer that has already
// been created, and just remove the prefix, rather than taking in a string and then // been created, and just remove the prefix, rather than taking in a string and then
// outputting a string buffer. // outputting a string buffer.
countryCode = maybeExtractCountryCode(nationalNumber.toString(), regionMetadata,
countryCode = maybeExtractCountryCode(nationalNumber, regionMetadata,
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);
if (e.getErrorType() == NumberParseException.ErrorType.INVALID_COUNTRY_CODE if (e.getErrorType() == NumberParseException.ErrorType.INVALID_COUNTRY_CODE
&& matcher.lookingAt()) { && matcher.lookingAt()) {
// Strip the plus-char, and try again. // Strip the plus-char, and try again.
@ -3223,8 +3193,7 @@ public class PhoneNumberUtil {
} else { } else {
// If no extracted country calling code, use the region supplied instead. The national number // If no extracted country calling code, use the region supplied instead. The national number
// is just the normalized version of the number we were given to parse. // is just the normalized version of the number we were given to parse.
normalize(nationalNumber);
normalizedNationalNumber.append(nationalNumber);
normalizedNationalNumber.append(normalize(nationalNumber));
if (defaultRegion != null) { if (defaultRegion != null) {
countryCode = regionMetadata.getCountryCode(); countryCode = regionMetadata.getCountryCode();
phoneNumber.setCountryCode(countryCode); phoneNumber.setCountryCode(countryCode);
@ -3243,8 +3212,7 @@ public class PhoneNumberUtil {
// 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
// long enough to be a possible length for the region. Otherwise, we don't do the stripping, // 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. // since the original number could be a valid short number.
if (testNumberLength(potentialNationalNumber.toString(), regionMetadata)
!= ValidationResult.TOO_SHORT) {
if (testNumberLength(potentialNationalNumber, regionMetadata) != ValidationResult.TOO_SHORT) {
normalizedNationalNumber = potentialNationalNumber; normalizedNationalNumber = potentialNationalNumber;
if (keepRawInput && carrierCode.length() > 0) { if (keepRawInput && carrierCode.length() > 0) {
phoneNumber.setPreferredDomesticCarrierCode(carrierCode.toString()); phoneNumber.setPreferredDomesticCarrierCode(carrierCode.toString());
@ -3260,7 +3228,7 @@ public class PhoneNumberUtil {
throw new NumberParseException(NumberParseException.ErrorType.TOO_LONG, throw new NumberParseException(NumberParseException.ErrorType.TOO_LONG,
"The string supplied is too long to be a phone number."); "The string supplied is too long to be a phone number.");
} }
setItalianLeadingZerosForPhoneNumber(normalizedNationalNumber.toString(), phoneNumber);
setItalianLeadingZerosForPhoneNumber(normalizedNationalNumber, phoneNumber);
phoneNumber.setNationalNumber(Long.parseLong(normalizedNationalNumber.toString())); phoneNumber.setNationalNumber(Long.parseLong(normalizedNationalNumber.toString()));
} }
@ -3413,7 +3381,7 @@ public class PhoneNumberUtil {
* @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
* {@link #isNumberMatch(PhoneNumber, PhoneNumber)} for more details. * {@link #isNumberMatch(PhoneNumber, PhoneNumber)} for more details.
*/ */
public MatchType isNumberMatch(String firstNumber, String secondNumber) {
public MatchType isNumberMatch(CharSequence firstNumber, CharSequence secondNumber) {
try { try {
PhoneNumber firstNumberAsProto = parse(firstNumber, UNKNOWN_REGION); PhoneNumber firstNumberAsProto = parse(firstNumber, UNKNOWN_REGION);
return isNumberMatch(firstNumberAsProto, secondNumber); return isNumberMatch(firstNumberAsProto, secondNumber);
@ -3451,7 +3419,7 @@ public class PhoneNumberUtil {
* @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
* {@link #isNumberMatch(PhoneNumber, PhoneNumber)} for more details. * {@link #isNumberMatch(PhoneNumber, PhoneNumber)} for more details.
*/ */
public MatchType isNumberMatch(PhoneNumber firstNumber, String secondNumber) {
public MatchType isNumberMatch(PhoneNumber firstNumber, CharSequence secondNumber) {
// First see if the second number has an implicit country calling code, by attempting to parse // First see if the second number has an implicit country calling code, by attempting to parse
// it. // it.
try { try {


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

@ -428,14 +428,14 @@ public class ShortNumberInfo {
* @param regionCode the region where the phone number is being dialed * @param regionCode the region where the phone number is being dialed
* @return whether the number exactly matches an emergency services number in the given region * @return whether the number exactly matches an emergency services number in the given region
*/ */
public boolean isEmergencyNumber(String number, String regionCode) {
public boolean isEmergencyNumber(CharSequence number, String regionCode) {
return matchesEmergencyNumberHelper(number, regionCode, false /* doesn't allow prefix match */); return matchesEmergencyNumberHelper(number, regionCode, false /* doesn't allow prefix match */);
} }
private boolean matchesEmergencyNumberHelper(String number, String regionCode,
private boolean matchesEmergencyNumberHelper(CharSequence number, String regionCode,
boolean allowPrefixMatch) { boolean allowPrefixMatch) {
number = PhoneNumberUtil.extractPossibleNumber(number);
if (PhoneNumberUtil.PLUS_CHARS_PATTERN.matcher(number).lookingAt()) {
CharSequence possibleNumber = PhoneNumberUtil.extractPossibleNumber(number);
if (PhoneNumberUtil.PLUS_CHARS_PATTERN.matcher(possibleNumber).lookingAt()) {
// Returns false if the number starts with a plus sign. We don't believe dialing the country // Returns false if the number starts with a plus sign. We don't believe dialing the country
// code before emergency numbers (e.g. +1911) works, but later, if that proves to work, we can // code before emergency numbers (e.g. +1911) works, but later, if that proves to work, we can
// add additional logic here to handle it. // add additional logic here to handle it.
@ -446,11 +446,10 @@ public class ShortNumberInfo {
return false; return false;
} }
String normalizedNumber = PhoneNumberUtil.normalizeDigitsOnly(number);
PhoneNumberDesc emergencyDesc = metadata.getEmergency();
String normalizedNumber = PhoneNumberUtil.normalizeDigitsOnly(possibleNumber);
boolean allowPrefixMatchForRegion = boolean allowPrefixMatchForRegion =
allowPrefixMatch && !REGIONS_WHERE_EMERGENCY_NUMBERS_MUST_BE_EXACT.contains(regionCode); allowPrefixMatch && !REGIONS_WHERE_EMERGENCY_NUMBERS_MUST_BE_EXACT.contains(regionCode);
return matcherApi.matchNationalNumber(normalizedNumber, emergencyDesc,
return matcherApi.matchNationalNumber(normalizedNumber, metadata.getEmergency(),
allowPrefixMatchForRegion); allowPrefixMatchForRegion);
} }


+ 8
- 12
java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java View File

@ -418,33 +418,29 @@ public class PhoneNumberUtilTest extends TestMetadataTestCase {
} }
public void testNormaliseRemovePunctuation() { public void testNormaliseRemovePunctuation() {
String inputNumber = "034-56&+#2\u00AD34";
StringBuilder inputNumber = new StringBuilder("034-56&+#2\u00AD34");
String expectedOutput = "03456234"; String expectedOutput = "03456234";
assertEquals("Conversion did not correctly remove punctuation", assertEquals("Conversion did not correctly remove punctuation",
expectedOutput,
PhoneNumberUtil.normalize(inputNumber));
expectedOutput, PhoneNumberUtil.normalize(inputNumber).toString());
} }
public void testNormaliseReplaceAlphaCharacters() { public void testNormaliseReplaceAlphaCharacters() {
String inputNumber = "034-I-am-HUNGRY";
StringBuilder inputNumber = new StringBuilder("034-I-am-HUNGRY");
String expectedOutput = "034426486479"; String expectedOutput = "034426486479";
assertEquals("Conversion did not correctly replace alpha characters", assertEquals("Conversion did not correctly replace alpha characters",
expectedOutput,
PhoneNumberUtil.normalize(inputNumber));
expectedOutput, PhoneNumberUtil.normalize(inputNumber).toString());
} }
public void testNormaliseOtherDigits() { public void testNormaliseOtherDigits() {
String inputNumber = "\uFF125\u0665";
StringBuilder inputNumber = new StringBuilder("\uFF125\u0665");
String expectedOutput = "255"; String expectedOutput = "255";
assertEquals("Conversion did not correctly replace non-latin digits", assertEquals("Conversion did not correctly replace non-latin digits",
expectedOutput,
PhoneNumberUtil.normalize(inputNumber));
expectedOutput, PhoneNumberUtil.normalize(inputNumber).toString());
// Eastern-Arabic digits. // Eastern-Arabic digits.
inputNumber = "\u06F52\u06F0";
inputNumber = new StringBuilder("\u06F52\u06F0");
expectedOutput = "520"; expectedOutput = "520";
assertEquals("Conversion did not correctly replace non-latin digits", assertEquals("Conversion did not correctly replace non-latin digits",
expectedOutput,
PhoneNumberUtil.normalize(inputNumber));
expectedOutput, PhoneNumberUtil.normalize(inputNumber).toString());
} }
public void testNormaliseStripAlphaCharacters() { public void testNormaliseStripAlphaCharacters() {


+ 10
- 0
pending_code_changes.txt View File

@ -8,3 +8,13 @@ Code changes:
- Documentation update for private variables VALID_PUNCTUATION and - Documentation update for private variables VALID_PUNCTUATION and
SINGLE_INTERNATIONAL_PREFIX, also renaming the latter from SINGLE_INTERNATIONAL_PREFIX, also renaming the latter from
UNIQUE_INTERNATIONAL_PREFIX. UNIQUE_INTERNATIONAL_PREFIX.
- [Java only] Changing public APIs that take in strings representing phone
numbers or parts of phone numbers to take in CharSequence instead. Updating
some of the internal methods to do the same. This affects ShortNumberInfo and
PhoneNumberUtil, namely the following methods:
- parse & parseAndKeepRawInput
- formatWithCarrierCode & formatWithPreferredCarrierCode
- isNumberMatch
- isPossibleNumber
- isAlphaNumber
- normalizeDigitsOnly & normalizeDiallableCharsOnly

Loading…
Cancel
Save