Browse Source

Update library to v2.2

pull/567/head
Shaopeng Jia 16 years ago
committed by Mihaela Rosca
parent
commit
d86a28ff8e
6 changed files with 436 additions and 65 deletions
  1. +1
    -1
      java/resources/com/google/i18n/phonenumbers/src/PhoneNumberMetaData.xml
  2. BIN
      java/resources/com/google/i18n/phonenumbers/src/generated_files/PhoneNumberMetadataProto
  3. +157
    -30
      java/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java
  4. +92
    -2
      java/src/com/google/i18n/phonenumbers/Phonenumber.java
  5. +25
    -0
      java/src/com/google/i18n/phonenumbers/phonenumber.proto
  6. +161
    -32
      java/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java

+ 1
- 1
java/resources/com/google/i18n/phonenumbers/src/PhoneNumberMetaData.xml View File

@ -3626,7 +3626,7 @@
<!-- Lithuania --> <!-- Lithuania -->
<!-- http://www.itu.int/oth/T020200007C/en --> <!-- http://www.itu.int/oth/T020200007C/en -->
<territory id="LT" countryCode="370" internationalPrefix="00" <territory id="LT" countryCode="370" internationalPrefix="00"
nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
nationalPrefix="8" nationalPrefixFormattingRule="$NP $FG">
<availableFormats> <availableFormats>
<!-- Two-digit area codes --> <!-- Two-digit area codes -->
<numberFormat leadingDigits="37|4(?:1|5[45]|6[2-4])" <numberFormat leadingDigits="37|4(?:1|5[45]|6[2-4])"


BIN
java/resources/com/google/i18n/phonenumbers/src/generated_files/PhoneNumberMetadataProto View File


+ 157
- 30
java/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java View File

@ -24,6 +24,7 @@ import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadataCollection; import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadataCollection;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc; import com.google.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc;
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource;
import com.google.protobuf.MessageLite; import com.google.protobuf.MessageLite;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -483,6 +484,90 @@ public class PhoneNumberUtil {
return normalizeHelper(number, ALL_NORMALIZATION_MAPPINGS, false); return normalizeHelper(number, ALL_NORMALIZATION_MAPPINGS, false);
} }
/**
* Gets the length of the geographical area code from the national_number field of the PhoneNumber
* object passed in, so that clients could use it to split a national significant number into
* geographical area code and subscriber number. It works in such a way that the resultant
* subscriber number should be diallable, at least on some devices. An example of how this could
* be used:
*
* PhoneNumberUtil phoneUtil.PhoneNumberUtil.getInstance();
* PhoneNumber number = phoneUtil.parse("16502530000", RegionCode.US);
* String nationalSignificantNumber = PhoneNumberUtil.getNationalSignificantNumber(number);
* String areaCode;
* String subscriberNumber;
*
* int areaCodeLength = phoneUtil.getLengthOfGeographicalAreaCode(number);
* if (areaCodeLength > 0) {
* areaCode = nationalSignificantNumber.substring(0, areaCodeLength);
* subscriberNumber = nationalSignificantNumber.substring(areaCodeLength);
* } else {
* areaCode = "";
* subscriberNumber = nationalSignificantNumber;
* }
*
* N.B.: area code is a very ambiguous concept, so the I18N team generally recommends against
* using it for most purposes, but recommends using the more general national_number instead. Read
* the following carefully before deciding to use this method:
*
* - geographical area codes change over time, and this method honors those changes; therefore,
* it doesn't guarantee the stability of the result it produces.
* - subscriber numbers may not be diallable from all devices (notably mobile devices, which
* typically requires the full national_number to be dialled in most countries).
* - most non-geographical numbers have no area codes.
* - some geographical numbers have no area codes.
*
* @param number the PhoneNumber object for which clients want to know the length of the area
* code in the national_number field.
* @return the length of area code of the PhoneNumber object passed in.
*/
public int getLengthOfGeographicalAreaCode(PhoneNumber number) {
String regionCode = getRegionCodeForNumber(number);
if (regionCode == null || regionCode.equalsIgnoreCase("ZZ")) {
return 0;
}
PhoneMetadata metadata = getMetadataForRegion(regionCode);
// For NANPA countries, national prefix is the same as country code, but it is not stored in
// the metadata.
if (!metadata.hasNationalPrefix() && !isNANPACountry(regionCode)) {
return 0;
}
PhoneNumberType type = getNumberTypeHelper(String.valueOf(number.getNationalNumber()),
metadata);
// Most numbers other than the two types below have to be dialled in full.
if (type != PhoneNumberType.FIXED_LINE && type != PhoneNumberType.FIXED_LINE_OR_MOBILE) {
return 0;
}
PhoneNumber copiedProto;
if (number.hasExtension()) {
// We don't want to alter the proto given to us, but we don't want to include the extension
// when we format it, so we copy it and clear the extension here.
PhoneNumber.Builder protoBuilder = PhoneNumber.newBuilder();
protoBuilder.mergeFrom(number);
protoBuilder.clearExtension();
copiedProto = protoBuilder.build();
} else {
copiedProto = number;
}
String nationalSignificantNumber = format(copiedProto,
PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL);
Pattern nonDigitPattern = Pattern.compile("(\\D+)");
String[] numberGroups = nonDigitPattern.split(nationalSignificantNumber);
// The pattern will start with "+COUNTRY_CODE " so the first group will always be the empty
// string (before the + symbol) and the second group will be the country code. The third group
// will be area code if it is not the last group.
if (numberGroups.length <= 3) {
return 0;
}
// Note all countries that use leading zero in national number don't use national prefix, so
// they won't have an area code, which means clients don't need to worry about appending the
// leading zero to the geographical area code they derive from the length we return here.
return numberGroups[2].length();
}
/** /**
* Normalizes a string of characters representing a phone number by replacing all characters found * Normalizes a string of characters representing a phone number by replacing all characters found
* 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
@ -494,7 +579,7 @@ public class PhoneNumberUtil {
* @param removeNonMatches indicates whether characters that are not able to be replaced * @param removeNonMatches indicates whether characters that are not able to be replaced
* should be stripped from the number. If this is false, they * should be stripped from the number. If this is false, they
* will be left unchanged in the number. * 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,
Map<Character, Character> normalizationReplacements, Map<Character, Character> normalizationReplacements,
@ -582,11 +667,11 @@ public class PhoneNumberUtil {
* *
* @param number the phone number to be formatted * @param number the phone number to be formatted
* @param numberFormat the format the phone number should be formatted into * @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) {
int countryCode = number.getCountryCode(); int countryCode = number.getCountryCode();
String nationalSignificantNumber = getUnformattedNationalNumber(number);
String nationalSignificantNumber = getNationalSignificantNumber(number);
if (numberFormat == PhoneNumberFormat.E164) { if (numberFormat == PhoneNumberFormat.E164) {
// Early exit for E164 case since no formatting of the national number needs to be applied. // Early exit for E164 case since no formatting of the national number needs to be applied.
// Extensions are not formatted. // Extensions are not formatted.
@ -617,7 +702,7 @@ public class PhoneNumberUtil {
* @param number the phone number to be formatted * @param number the phone number to be formatted
* @param numberFormat the format the phone number should be formatted into * @param numberFormat the format the phone number should be formatted into
* @param userDefinedFormats formatting rules specified by clients * @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,
PhoneNumberFormat numberFormat, PhoneNumberFormat numberFormat,
@ -627,7 +712,7 @@ public class PhoneNumberUtil {
// share a country code is contained by only one country for performance reasons. For example, // share a country code is contained by only one country for performance reasons. For example,
// for NANPA countries it will be contained in the metadata for US. // for NANPA countries it will be contained in the metadata for US.
String regionCode = getRegionCodeForCountryCode(countryCode); String regionCode = getRegionCodeForCountryCode(countryCode);
String nationalSignificantNumber = getUnformattedNationalNumber(number);
String nationalSignificantNumber = getNationalSignificantNumber(number);
if (!isValidRegionCode(regionCode, countryCode, nationalSignificantNumber)) { if (!isValidRegionCode(regionCode, countryCode, nationalSignificantNumber)) {
return nationalSignificantNumber; return nationalSignificantNumber;
} }
@ -671,7 +756,7 @@ public class PhoneNumberUtil {
* @param number the phone number to be formatted * @param number the phone number to be formatted
* @param countryCallingFrom the ISO 3166-1 two-letter country code that denotes the foreign * @param countryCallingFrom the ISO 3166-1 two-letter country code that denotes the foreign
* country where the call is being placed * country 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,
String countryCallingFrom) { String countryCallingFrom) {
@ -720,7 +805,7 @@ public class PhoneNumberUtil {
} else { } else {
regionCode = getRegionCodeForCountryCode(countryCode); regionCode = getRegionCodeForCountryCode(countryCode);
} }
String nationalSignificantNumber = getUnformattedNationalNumber(number);
String nationalSignificantNumber = getNationalSignificantNumber(number);
if (!isValidRegionCode(regionCode, countryCode, nationalSignificantNumber)) { if (!isValidRegionCode(regionCode, countryCode, nationalSignificantNumber)) {
return nationalSignificantNumber; return nationalSignificantNumber;
} }
@ -750,7 +835,15 @@ public class PhoneNumberUtil {
formattedExtension); formattedExtension);
} }
static String getUnformattedNationalNumber(PhoneNumber number) {
/**
* Gets the national significant number of the a phone number. Note a national significant number
* doesn't contain a national prefix or any formatting.
*
* @param number the PhoneNumber object for which the national significant number is needed
* @return the national significant number of the PhoneNumber object passed in
*/
public static String getNationalSignificantNumber(PhoneNumber number) {
// The leading zero in the national (significant) number of an Italian phone number has a // The leading zero in the national (significant) number of an Italian phone number has a
// special meaning. Unlike the rest of the world, it indicates the number is a landline // special meaning. Unlike the rest of the world, it indicates the number is a landline
// number. There have been plans to migrate landline numbers to start with the digit two since // number. There have been plans to migrate landline numbers to start with the digit two since
@ -921,7 +1014,7 @@ public class PhoneNumberUtil {
*/ */
public PhoneNumberType getNumberType(PhoneNumber number) { public PhoneNumberType getNumberType(PhoneNumber number) {
String regionCode = getRegionCodeForNumber(number); String regionCode = getRegionCodeForNumber(number);
String nationalSignificantNumber = getUnformattedNationalNumber(number);
String nationalSignificantNumber = getNationalSignificantNumber(number);
if (!isValidRegionCode(regionCode, number.getCountryCode(), nationalSignificantNumber)) { if (!isValidRegionCode(regionCode, number.getCountryCode(), nationalSignificantNumber)) {
return PhoneNumberType.UNKNOWN; return PhoneNumberType.UNKNOWN;
} }
@ -1007,7 +1100,7 @@ public class PhoneNumberUtil {
public boolean isValidNumber(PhoneNumber number) { public boolean isValidNumber(PhoneNumber number) {
String regionCode = getRegionCodeForNumber(number); String regionCode = getRegionCodeForNumber(number);
return isValidRegionCode(regionCode, number.getCountryCode(), return isValidRegionCode(regionCode, number.getCountryCode(),
getUnformattedNationalNumber(number))
getNationalSignificantNumber(number))
&& isValidNumberForRegion(number, regionCode); && isValidNumberForRegion(number, regionCode);
} }
@ -1031,7 +1124,7 @@ public class PhoneNumberUtil {
} }
PhoneMetadata metadata = getMetadataForRegion(regionCode); PhoneMetadata metadata = getMetadataForRegion(regionCode);
PhoneNumberDesc generalNumDesc = metadata.getGeneralDesc(); PhoneNumberDesc generalNumDesc = metadata.getGeneralDesc();
String nationalSignificantNumber = getUnformattedNationalNumber(number);
String nationalSignificantNumber = getNationalSignificantNumber(number);
// For countries where we don't have metadata for PhoneNumberDesc, we treat any number passed // For countries where we don't have metadata for PhoneNumberDesc, we treat any number passed
// in as a valid number if its national significant number is between the minimum and maximum // in as a valid number if its national significant number is between the minimum and maximum
@ -1058,7 +1151,9 @@ public class PhoneNumberUtil {
case NANPA_COUNTRY_CODE: case NANPA_COUNTRY_CODE:
// Override this and try the US case first, since it is more likely than other countries, // Override this and try the US case first, since it is more likely than other countries,
// for performance reasons. // for performance reasons.
if (isValidNumberForRegion(number, "US")) {
String nationalNumber = getNationalSignificantNumber(number);
if (getNumberTypeHelper(nationalNumber,
getMetadataForRegion("US")) != PhoneNumberType.UNKNOWN) {
return "US"; return "US";
} }
Set<String> nanpaExceptUS = new HashSet<String>(nanpaCountries); Set<String> nanpaExceptUS = new HashSet<String>(nanpaCountries);
@ -1165,7 +1260,7 @@ public class PhoneNumberUtil {
* @return a ValidationResult object which indicates whether the number is possible * @return a ValidationResult object which indicates whether the number is possible
*/ */
public ValidationResult isPossibleNumberWithReason(PhoneNumber number) { public ValidationResult isPossibleNumberWithReason(PhoneNumber number) {
String nationalNumber = getUnformattedNationalNumber(number);
String nationalNumber = getNationalSignificantNumber(number);
int countryCode = number.getCountryCode(); int countryCode = number.getCountryCode();
// Note: For Russian Fed and NANPA numbers, we just use the rules from the default region (US or // Note: For Russian Fed and NANPA numbers, we just use the rules from the default region (US or
// Russia) since the getRegionCodeForNumber will not work if the number is possible but not // Russia) since the getRegionCodeForNumber will not work if the number is possible but not
@ -1272,19 +1367,34 @@ public class PhoneNumberUtil {
* @param nationalNumber a string buffer to store the national significant number in, in the case * @param nationalNumber a string buffer to store the national significant number in, in the case
* that a country code was extracted. The number is appended to any existing contents. If no * that a country code was extracted. The number is appended to any existing contents. If no
* country code was extracted, this will be left unchanged. * country code was extracted, this will be left unchanged.
* @param storeCountryCodeSource true if the country_code_source field of phoneNumber should be
* populated.
* @param phoneNumber the PhoneNumber.Builder object that needs to be populated with country code
* and country code source. Note the country code is always populated, whereas country code
* source is only populated when keepCountryCodeSource is true.
* @return the country code extracted or 0 if none could be extracted * @return the country code extracted or 0 if none could be extracted
*/ */
@VisibleForTesting @VisibleForTesting
int maybeExtractCountryCode(String number, PhoneMetadata defaultRegionMetadata, int maybeExtractCountryCode(String number, PhoneMetadata defaultRegionMetadata,
StringBuffer nationalNumber)
StringBuffer nationalNumber, boolean storeCountryCodeSource,
PhoneNumber.Builder phoneNumber)
throws NumberParseException { throws NumberParseException {
if (number.length() == 0) {
return 0;
}
StringBuffer fullNumber = new StringBuffer(number); StringBuffer fullNumber = new StringBuffer(number);
// Set the default prefix to be something that will never match. // Set the default prefix to be something that will never match.
String possibleCountryIddPrefix = "NonMatch"; String possibleCountryIddPrefix = "NonMatch";
if (defaultRegionMetadata != null) { if (defaultRegionMetadata != null) {
possibleCountryIddPrefix = defaultRegionMetadata.getInternationalPrefix(); possibleCountryIddPrefix = defaultRegionMetadata.getInternationalPrefix();
} }
if (maybeStripInternationalPrefixAndNormalize(fullNumber, possibleCountryIddPrefix)) {
CountryCodeSource countryCodeSource =
maybeStripInternationalPrefixAndNormalize(fullNumber, possibleCountryIddPrefix);
if (storeCountryCodeSource) {
phoneNumber.setCountryCodeSource(countryCodeSource);
}
if (countryCodeSource != CountryCodeSource.FROM_DEFAULT_COUNTRY) {
if (fullNumber.length() < MIN_LENGTH_FOR_NSN) { if (fullNumber.length() < MIN_LENGTH_FOR_NSN) {
throw new NumberParseException(NumberParseException.ErrorType.TOO_SHORT_AFTER_IDD, throw new NumberParseException(NumberParseException.ErrorType.TOO_SHORT_AFTER_IDD,
"Phone number had an IDD, but after this was not " "Phone number had an IDD, but after this was not "
@ -1292,6 +1402,7 @@ public class PhoneNumberUtil {
} }
int potentialCountryCode = extractCountryCode(fullNumber, nationalNumber); int potentialCountryCode = extractCountryCode(fullNumber, nationalNumber);
if (potentialCountryCode != 0) { if (potentialCountryCode != 0) {
phoneNumber.setCountryCode(potentialCountryCode);
return potentialCountryCode; return potentialCountryCode;
} }
@ -1319,12 +1430,17 @@ public class PhoneNumberUtil {
validNumberPattern); validNumberPattern);
if (validNumberPattern.matcher(potentialNationalNumber).matches()) { if (validNumberPattern.matcher(potentialNationalNumber).matches()) {
nationalNumber.append(potentialNationalNumber); nationalNumber.append(potentialNationalNumber);
if (storeCountryCodeSource) {
phoneNumber.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN);
}
phoneNumber.setCountryCode(defaultCountryCode);
return defaultCountryCode; return defaultCountryCode;
} }
} }
} }
} }
// No country code present. // No country code present.
phoneNumber.setCountryCode(0);
return 0; return 0;
} }
@ -1332,8 +1448,7 @@ public class PhoneNumberUtil {
* Strips the IDD from the start of the number if present. Helper function used by * Strips the IDD from the start of the number if present. Helper function used by
* maybeStripInternationalPrefixAndNormalize. * maybeStripInternationalPrefixAndNormalize.
*/ */
private boolean parsePrefixAsIdd(Pattern iddPattern,
StringBuffer number) {
private boolean parsePrefixAsIdd(Pattern iddPattern, StringBuffer number) {
Matcher m = iddPattern.matcher(number); Matcher m = iddPattern.matcher(number);
if (m.lookingAt()) { if (m.lookingAt()) {
int matchEnd = m.end(); int matchEnd = m.end();
@ -1360,31 +1475,36 @@ public class PhoneNumberUtil {
* dialing prefix from * dialing prefix from
* @param possibleIddPrefix the international direct dialing prefix from the country we * @param possibleIddPrefix the international direct dialing prefix from the country we
* think this number may be dialed in * think this number may be dialed in
* @return true if an international dialing prefix could be removed from the number, otherwise
* false if the number did not seem to be in international format
* @return the corresponding CountryCodeSource if an international dialing prefix could be
* removed from the number, otherwise CountryCodeSource.FROM_DEFAULT_COUNTRY if the number
* did not seem to be in international format.
*/ */
@VisibleForTesting @VisibleForTesting
boolean maybeStripInternationalPrefixAndNormalize(StringBuffer number, String possibleIddPrefix) {
CountryCodeSource maybeStripInternationalPrefixAndNormalize(
StringBuffer number,
String possibleIddPrefix) {
if (number.length() == 0) { if (number.length() == 0) {
return false;
return CountryCodeSource.FROM_DEFAULT_COUNTRY;
} }
if (number.charAt(0) == PLUS_SIGN) { if (number.charAt(0) == PLUS_SIGN) {
number.deleteCharAt(0); number.deleteCharAt(0);
// Can now normalize the rest of the number since we've consumed the "+" sign at the start. // Can now normalize the rest of the number since we've consumed the "+" sign at the start.
normalize(number); normalize(number);
return true;
return CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN;
} }
// Attempt to parse the first digits as an international prefix. // Attempt to parse the first digits as an international prefix.
Pattern iddPattern = Pattern.compile(possibleIddPrefix); Pattern iddPattern = Pattern.compile(possibleIddPrefix);
if (parsePrefixAsIdd(iddPattern, number)) { if (parsePrefixAsIdd(iddPattern, number)) {
normalize(number); normalize(number);
return true;
return CountryCodeSource.FROM_NUMBER_WITH_IDD;
} }
// If still not found, then try and normalize the number and then try again. This shouldn't be // If still not found, then try and normalize the number and then try again. This shouldn't be
// done before, since non-numeric characters (+ and ~) may legally be in the international // done before, since non-numeric characters (+ and ~) may legally be in the international
// prefix. // prefix.
normalize(number); normalize(number);
return parsePrefixAsIdd(iddPattern, number);
return parsePrefixAsIdd(iddPattern, number)
? CountryCodeSource.FROM_NUMBER_WITH_IDD
: CountryCodeSource.FROM_DEFAULT_COUNTRY;
} }
/** /**
@ -1489,7 +1609,8 @@ public class PhoneNumberUtil {
/** /**
* Parses a string and returns it in proto buffer format. This method differs from parse() in that * Parses a string and returns it in proto buffer format. This method differs from parse() in that
* it always populates the raw_input field of the protocol buffer with numberToParse.
* it always populates the raw_input field of the protocol buffer with numberToParse as well as
* the country_code_source field.
* *
* @param numberToParse number that we are attempting to parse. This can contain formatting * @param numberToParse number that we are attempting to parse. This can contain formatting
* such as +, ( and -, as well as a phone number extension. * such as +, ( and -, as well as a phone number extension.
@ -1571,10 +1692,12 @@ public class PhoneNumberUtil {
// been created, and just remove the prefix, rather than taking in a string and then outputting // been created, and just remove the prefix, rather than taking in a string and then outputting
// a string buffer. // a string buffer.
int countryCode = maybeExtractCountryCode(nationalNumber.toString(), countryMetadata, int countryCode = maybeExtractCountryCode(nationalNumber.toString(), countryMetadata,
normalizedNationalNumber);
normalizedNationalNumber, keepRawInput, phoneNumber);
if (countryCode != 0) { if (countryCode != 0) {
String phoneNumberRegion = getRegionCodeForCountryCode(countryCode); String phoneNumberRegion = getRegionCodeForCountryCode(countryCode);
countryMetadata = getMetadataForRegion(phoneNumberRegion);
if (!phoneNumberRegion.equals(defaultCountry)) {
countryMetadata = getMetadataForRegion(phoneNumberRegion);
}
} else { } else {
// If no extracted country code, use the region supplied instead. The national number is just // If no extracted country code, use the region supplied instead. The national number is just
// the normalized version of the number we were given to parse. // the normalized version of the number we were given to parse.
@ -1582,6 +1705,9 @@ public class PhoneNumberUtil {
normalizedNationalNumber.append(nationalNumber); normalizedNationalNumber.append(nationalNumber);
if (defaultCountry != null) { if (defaultCountry != null) {
countryCode = countryMetadata.getCountryCode(); countryCode = countryMetadata.getCountryCode();
phoneNumber.setCountryCode(countryCode);
} else if (keepRawInput) {
phoneNumber.clearCountryCodeSource();
} }
} }
if (normalizedNationalNumber.length() < MIN_LENGTH_FOR_NSN) { if (normalizedNationalNumber.length() < MIN_LENGTH_FOR_NSN) {
@ -1607,7 +1733,6 @@ public class PhoneNumberUtil {
"The string supplied is too long to be a " "The string supplied is too long to be a "
+ "phone number."); + "phone number.");
} }
phoneNumber.setCountryCode(countryCode);
if (isLeadingZeroCountry(countryCode) && if (isLeadingZeroCountry(countryCode) &&
normalizedNationalNumber.charAt(0) == '0') { normalizedNationalNumber.charAt(0) == '0') {
phoneNumber.setItalianLeadingZero(true); phoneNumber.setItalianLeadingZero(true);
@ -1642,10 +1767,12 @@ public class PhoneNumberUtil {
firstNumber.mergeFrom(firstNumberIn); firstNumber.mergeFrom(firstNumberIn);
PhoneNumber.Builder secondNumber = PhoneNumber.newBuilder(); PhoneNumber.Builder secondNumber = PhoneNumber.newBuilder();
secondNumber.mergeFrom(secondNumberIn); secondNumber.mergeFrom(secondNumberIn);
// First clear raw_input field and any empty-string extensions so that we can use the
// proto-buffer equality method.
// First clear raw_input and country_code_source field and any empty-string extensions so that
// we can use the proto-buffer equality method.
firstNumber.clearRawInput(); firstNumber.clearRawInput();
firstNumber.clearCountryCodeSource();
secondNumber.clearRawInput(); secondNumber.clearRawInput();
secondNumber.clearCountryCodeSource();
if (firstNumber.hasExtension() && if (firstNumber.hasExtension() &&
firstNumber.getExtension().equals("")) { firstNumber.getExtension().equals("")) {
firstNumber.clearExtension(); firstNumber.clearExtension();


+ 92
- 2
java/src/com/google/i18n/phonenumbers/Phonenumber.java View File

@ -25,6 +25,49 @@ public final class Phonenumber {
return defaultInstance; return defaultInstance;
} }
public enum CountryCodeSource
implements com.google.protobuf.Internal.EnumLite {
FROM_NUMBER_WITH_PLUS_SIGN(0, 1),
FROM_NUMBER_WITH_IDD(1, 5),
FROM_NUMBER_WITHOUT_PLUS_SIGN(2, 10),
FROM_DEFAULT_COUNTRY(3, 20),
;
public final int getNumber() { return value; }
public static CountryCodeSource valueOf(int value) {
switch (value) {
case 1: return FROM_NUMBER_WITH_PLUS_SIGN;
case 5: return FROM_NUMBER_WITH_IDD;
case 10: return FROM_NUMBER_WITHOUT_PLUS_SIGN;
case 20: return FROM_DEFAULT_COUNTRY;
default: return null;
}
}
public static com.google.protobuf.Internal.EnumLiteMap<CountryCodeSource>
internalGetValueMap() {
return internalValueMap;
}
private static com.google.protobuf.Internal.EnumLiteMap<CountryCodeSource>
internalValueMap =
new com.google.protobuf.Internal.EnumLiteMap<CountryCodeSource>() {
public CountryCodeSource findValueByNumber(int number) {
return CountryCodeSource.valueOf(number)
; }
};
private final int index;
private final int value;
private CountryCodeSource(int index, int value) {
this.index = index;
this.value = value;
}
// @@protoc_insertion_point(enum_scope:i18n.phonenumbers.PhoneNumber.CountryCodeSource)
}
// required int32 country_code = 1; // required int32 country_code = 1;
public static final int COUNTRY_CODE_FIELD_NUMBER = 1; public static final int COUNTRY_CODE_FIELD_NUMBER = 1;
private boolean hasCountryCode; private boolean hasCountryCode;
@ -59,8 +102,16 @@ public final class Phonenumber {
private java.lang.String rawInput_ = ""; private java.lang.String rawInput_ = "";
public boolean hasRawInput() { return hasRawInput; } public boolean hasRawInput() { return hasRawInput; }
public java.lang.String getRawInput() { return rawInput_; } public java.lang.String getRawInput() { return rawInput_; }
// optional .i18n.phonenumbers.PhoneNumber.CountryCodeSource country_code_source = 6;
public static final int COUNTRY_CODE_SOURCE_FIELD_NUMBER = 6;
private boolean hasCountryCodeSource;
private com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource countryCodeSource_;
public boolean hasCountryCodeSource() { return hasCountryCodeSource; }
public com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource getCountryCodeSource() { return countryCodeSource_; }
private void initFields() { private void initFields() {
countryCodeSource_ = com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN;
} }
public final boolean isInitialized() { public final boolean isInitialized() {
if (!hasCountryCode) return false; if (!hasCountryCode) return false;
@ -86,6 +137,9 @@ public final class Phonenumber {
if (hasRawInput()) { if (hasRawInput()) {
output.writeString(5, getRawInput()); output.writeString(5, getRawInput());
} }
if (hasCountryCodeSource()) {
output.writeEnum(6, getCountryCodeSource().getNumber());
}
} }
private int memoizedSerializedSize = -1; private int memoizedSerializedSize = -1;
@ -114,6 +168,10 @@ public final class Phonenumber {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeStringSize(5, getRawInput()); .computeStringSize(5, getRawInput());
} }
if (hasCountryCodeSource()) {
size += com.google.protobuf.CodedOutputStream
.computeEnumSize(6, getCountryCodeSource().getNumber());
}
memoizedSerializedSize = size; memoizedSerializedSize = size;
return size; return size;
} }
@ -273,6 +331,9 @@ public final class Phonenumber {
if (other.hasRawInput()) { if (other.hasRawInput()) {
setRawInput(other.getRawInput()); setRawInput(other.getRawInput());
} }
if (other.hasCountryCodeSource()) {
setCountryCodeSource(other.getCountryCodeSource());
}
return this; return this;
} }
@ -311,6 +372,14 @@ public final class Phonenumber {
setRawInput(input.readString()); setRawInput(input.readString());
break; break;
} }
case 48: {
int rawValue = input.readEnum();
com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource value = com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource.valueOf(rawValue);
if (value != null) {
setCountryCodeSource(value);
}
break;
}
} }
} }
} }
@ -411,7 +480,28 @@ public final class Phonenumber {
result.rawInput_ = getDefaultInstance().getRawInput(); result.rawInput_ = getDefaultInstance().getRawInput();
return this; return this;
} }
// optional .i18n.phonenumbers.PhoneNumber.CountryCodeSource country_code_source = 6;
public boolean hasCountryCodeSource() {
return result.hasCountryCodeSource();
}
public com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource getCountryCodeSource() {
return result.getCountryCodeSource();
}
public Builder setCountryCodeSource(com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource value) {
if (value == null) {
throw new NullPointerException();
}
result.hasCountryCodeSource = true;
result.countryCodeSource_ = value;
return this;
}
public Builder clearCountryCodeSource() {
result.hasCountryCodeSource = false;
result.countryCodeSource_ = com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN;
return this;
}
// @@protoc_insertion_point(builder_scope:i18n.phonenumbers.PhoneNumber) // @@protoc_insertion_point(builder_scope:i18n.phonenumbers.PhoneNumber)
} }


+ 25
- 0
java/src/com/google/i18n/phonenumbers/phonenumber.proto View File

@ -55,6 +55,31 @@ message PhoneNumber {
// canonicalized by the library. For example, it could be used to store alphanumerical numbers // canonicalized by the library. For example, it could be used to store alphanumerical numbers
// such as "1-800-GOOG-411". // such as "1-800-GOOG-411".
optional string raw_input = 5; optional string raw_input = 5;
// The source from which the country_code is derived. This is not set in the general parsing method,
// but in the method that parses and keeps raw_input. New fields could be added upon request.
enum CountryCodeSource {
// The country_code is derived based on a phone number with a leading "+", e.g. the French
// number "+33 (0)1 42 68 53 00".
FROM_NUMBER_WITH_PLUS_SIGN = 1;
// The country_code is derived based on a phone number with a leading IDD, e.g. the French
// number "011 33 (0)1 42 68 53 00", as it is dialled from US.
FROM_NUMBER_WITH_IDD = 5;
// The country_code is derived based on a phone number without a leading "+", e.g. the French
// number "33 (0)1 42 68 53 00" when defaultCountry is supplied as France.
FROM_NUMBER_WITHOUT_PLUS_SIGN = 10;
// The country_code is derived NOT based on the phone number itself, but from the defaultCountry
// parameter provided in the parsing function by the clients. This happens mostly for numbers
// written in the national format (without country code). For example, this would be set when
// parsing the French number "(0)1 42 68 53 00", when defaultCountry is supplied as France.
FROM_DEFAULT_COUNTRY = 20;
}
// The source from which the country_code is derived.
optional CountryCodeSource country_code_source = 6;
} }
// Examples // Examples


+ 161
- 32
java/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java View File

@ -19,6 +19,7 @@ package com.google.i18n.phonenumbers;
import com.google.i18n.phonenumbers.Phonemetadata.NumberFormat; import com.google.i18n.phonenumbers.Phonemetadata.NumberFormat;
import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata; import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource;
import com.google.protobuf.MessageLite; import com.google.protobuf.MessageLite;
import junit.framework.TestCase; import junit.framework.TestCase;
@ -103,6 +104,8 @@ public class PhoneNumberUtilTest extends TestCase {
assertEquals("900([135]\\d{6}|9\\d{7})", metadata.getPremiumRate().getNationalNumberPattern()); assertEquals("900([135]\\d{6}|9\\d{7})", metadata.getPremiumRate().getNationalNumberPattern());
} }
public void testGetInstanceLoadARMetadata() { public void testGetInstanceLoadARMetadata() {
PhoneMetadata metadata = phoneUtil.getMetadataForRegion("AR"); PhoneMetadata metadata = phoneUtil.getMetadataForRegion("AR");
assertEquals("AR", metadata.getId()); assertEquals("AR", metadata.getId());
@ -119,6 +122,64 @@ public class PhoneNumberUtilTest extends TestCase {
assertEquals("$1 $2 $3 $4", metadata.getIntlNumberFormat(3).getFormat()); assertEquals("$1 $2 $3 $4", metadata.getIntlNumberFormat(3).getFormat());
} }
public void testGetLengthOfGeographicalAreaCode() {
// Google MTV, which has area code "650".
PhoneNumber usNumber1 =
PhoneNumber.newBuilder().setCountryCode(1).setNationalNumber(6502530000L).build();
assertEquals(3, phoneUtil.getLengthOfGeographicalAreaCode(usNumber1));
// A North America toll-free number, which has no area code.
PhoneNumber usNumber2 =
PhoneNumber.newBuilder().setCountryCode(1).setNationalNumber(8002530000L).build();
assertEquals(0, phoneUtil.getLengthOfGeographicalAreaCode(usNumber2));
// An invalid US number (1 digit shorter), which has no area code.
PhoneNumber usNumber3 =
PhoneNumber.newBuilder().setCountryCode(1).setNationalNumber(650253000L).build();
assertEquals(0, phoneUtil.getLengthOfGeographicalAreaCode(usNumber3));
// Google London, which has area code "20".
PhoneNumber ukNumber1 =
PhoneNumber.newBuilder().setCountryCode(44).setNationalNumber(2070313000L).build();
assertEquals(2, phoneUtil.getLengthOfGeographicalAreaCode(ukNumber1));
// A UK mobile phone, which has no area code.
PhoneNumber ukNumber2 =
PhoneNumber.newBuilder().setCountryCode(44).setNationalNumber(7123456789L).build();
assertEquals(0, phoneUtil.getLengthOfGeographicalAreaCode(ukNumber2));
// Google Buenos Aires, which has area code "11".
PhoneNumber arNumber =
PhoneNumber.newBuilder().setCountryCode(54).setNationalNumber(1155303000L).build();
assertEquals(2, phoneUtil.getLengthOfGeographicalAreaCode(arNumber));
// Google Sydney, which has area code "2".
PhoneNumber auNumber =
PhoneNumber.newBuilder().setCountryCode(61).setNationalNumber(293744000L).build();
assertEquals(1, phoneUtil.getLengthOfGeographicalAreaCode(auNumber));
// Google Singapore. Singapore has no area code and no national prefix.
PhoneNumber sgNumber =
PhoneNumber.newBuilder().setCountryCode(65).setNationalNumber(65218000L).build();
assertEquals(0, phoneUtil.getLengthOfGeographicalAreaCode(sgNumber));
}
public void testGetNationalSignificantNumber() {
PhoneNumber usNumber =
PhoneNumber.newBuilder().setCountryCode(1).setNationalNumber(6502530000L).build();
assertEquals("6502530000", PhoneNumberUtil.getNationalSignificantNumber(usNumber));
// An Italian mobile number.
PhoneNumber itNumber1 =
PhoneNumber.newBuilder().setCountryCode(39).setNationalNumber(312345678L).build();
assertEquals("312345678", PhoneNumberUtil.getNationalSignificantNumber(itNumber1));
// An Italian fixed line number.
PhoneNumber itNumber2 =
PhoneNumber.newBuilder().setCountryCode(39).setNationalNumber(236618300L).setItalianLeadingZero(true).build();
assertEquals("0236618300", PhoneNumberUtil.getNationalSignificantNumber(itNumber2));
}
public void testGetExampleNumber() throws IOException { public void testGetExampleNumber() throws IOException {
PhoneNumber deNumber = PhoneNumber deNumber =
PhoneNumber.newBuilder().setCountryCode(49).setNationalNumber(30123456).build(); PhoneNumber.newBuilder().setCountryCode(49).setNationalNumber(30123456).build();
@ -902,56 +963,67 @@ public class PhoneNumberUtilTest extends TestCase {
strippedNumber, numberToStrip.toString()); strippedNumber, numberToStrip.toString());
} }
public void testMaybeStripInternationalPrefix() {
public void testMaybeStripInternationalPrefix() {
String internationalPrefix = "00[39]"; String internationalPrefix = "00[39]";
StringBuffer numberToStrip = new StringBuffer("0034567700-3898003"); StringBuffer numberToStrip = new StringBuffer("0034567700-3898003");
// Note the dash is removed as part of the normalization. // Note the dash is removed as part of the normalization.
StringBuffer strippedNumber = new StringBuffer("45677003898003"); StringBuffer strippedNumber = new StringBuffer("45677003898003");
assertEquals(true, phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
assertEquals(CountryCodeSource.FROM_NUMBER_WITH_IDD,
phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
assertEquals("The number supplied was not stripped of its international prefix.", assertEquals("The number supplied was not stripped of its international prefix.",
strippedNumber.toString(), numberToStrip.toString()); strippedNumber.toString(), numberToStrip.toString());
// Now the number no longer starts with an IDD prefix, so it should now report false.
assertEquals(false, phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
// Now the number no longer starts with an IDD prefix, so it should now report
// FROM_DEFAULT_COUNTRY.
assertEquals(CountryCodeSource.FROM_DEFAULT_COUNTRY,
phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
numberToStrip = new StringBuffer("00945677003898003"); numberToStrip = new StringBuffer("00945677003898003");
assertEquals(true, phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
assertEquals(CountryCodeSource.FROM_NUMBER_WITH_IDD,
phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
assertEquals("The number supplied was not stripped of its international prefix.", assertEquals("The number supplied was not stripped of its international prefix.",
strippedNumber.toString(), numberToStrip.toString()); strippedNumber.toString(), numberToStrip.toString());
// Test it works when the international prefix is broken up by spaces. // Test it works when the international prefix is broken up by spaces.
numberToStrip = new StringBuffer("00 9 45677003898003"); numberToStrip = new StringBuffer("00 9 45677003898003");
assertEquals(true, phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
assertEquals(CountryCodeSource.FROM_NUMBER_WITH_IDD,
phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
assertEquals("The number supplied was not stripped of its international prefix.", assertEquals("The number supplied was not stripped of its international prefix.",
strippedNumber.toString(), numberToStrip.toString()); strippedNumber.toString(), numberToStrip.toString());
// Now the number no longer starts with an IDD prefix, so it should now report false.
assertEquals(false, phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
// Now the number no longer starts with an IDD prefix, so it should now report
// FROM_DEFAULT_COUNTRY.
assertEquals(CountryCodeSource.FROM_DEFAULT_COUNTRY,
phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
// Test the + symbol is also recognised and stripped. // Test the + symbol is also recognised and stripped.
numberToStrip = new StringBuffer("+45677003898003"); numberToStrip = new StringBuffer("+45677003898003");
strippedNumber = new StringBuffer("45677003898003"); strippedNumber = new StringBuffer("45677003898003");
assertEquals(true, phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
assertEquals(CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN,
phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
assertEquals("The number supplied was not stripped of the plus symbol.", assertEquals("The number supplied was not stripped of the plus symbol.",
strippedNumber.toString(), numberToStrip.toString()); strippedNumber.toString(), numberToStrip.toString());
// If the number afterwards is a zero, we should not strip this - no country code begins with 0. // If the number afterwards is a zero, we should not strip this - no country code begins with 0.
numberToStrip = new StringBuffer("0090112-3123"); numberToStrip = new StringBuffer("0090112-3123");
strippedNumber = new StringBuffer("00901123123"); strippedNumber = new StringBuffer("00901123123");
assertEquals(false, phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
assertEquals(CountryCodeSource.FROM_DEFAULT_COUNTRY,
phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
assertEquals("The number supplied had a 0 after the match so shouldn't be stripped.", assertEquals("The number supplied had a 0 after the match so shouldn't be stripped.",
strippedNumber.toString(), numberToStrip.toString()); strippedNumber.toString(), numberToStrip.toString());
// Here the 0 is separated by a space from the IDD. // Here the 0 is separated by a space from the IDD.
numberToStrip = new StringBuffer("009 0-112-3123"); numberToStrip = new StringBuffer("009 0-112-3123");
assertEquals(false, phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
assertEquals(CountryCodeSource.FROM_DEFAULT_COUNTRY,
phoneUtil.maybeStripInternationalPrefixAndNormalize(numberToStrip,
internationalPrefix));
} }
public void testMaybeExtractCountryCode() { public void testMaybeExtractCountryCode() {
PhoneNumber.Builder number = PhoneNumber.newBuilder();
PhoneMetadata metadata = phoneUtil.getMetadataForRegion("US"); PhoneMetadata metadata = phoneUtil.getMetadataForRegion("US");
// Note that for the US, the IDD is 011. // Note that for the US, the IDD is 011.
try { try {
@ -961,7 +1033,10 @@ public class PhoneNumberUtilTest extends TestCase {
StringBuffer numberToFill = new StringBuffer(); StringBuffer numberToFill = new StringBuffer();
assertEquals("Did not extract country code " + countryCode + " correctly.", assertEquals("Did not extract country code " + countryCode + " correctly.",
countryCode, countryCode,
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata, numberToFill));
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata, numberToFill, true,
number));
assertEquals("Did not figure out CountryCodeSource correctly",
CountryCodeSource.FROM_NUMBER_WITH_IDD, number.getCountryCodeSource());
// Should strip and normalize national significant number. // Should strip and normalize national significant number.
assertEquals("Did not strip off the country code correctly.", assertEquals("Did not strip off the country code correctly.",
strippedNumber, strippedNumber,
@ -969,30 +1044,38 @@ public class PhoneNumberUtilTest extends TestCase {
} catch (NumberParseException e) { } catch (NumberParseException e) {
fail("Should not have thrown an exception: " + e.toString()); fail("Should not have thrown an exception: " + e.toString());
} }
number.clear();
try { try {
String phoneNumber = "+6423456789"; String phoneNumber = "+6423456789";
int countryCode = 64; int countryCode = 64;
StringBuffer numberToFill = new StringBuffer(); StringBuffer numberToFill = new StringBuffer();
assertEquals("Did not extract country code " + countryCode + " correctly.", assertEquals("Did not extract country code " + countryCode + " correctly.",
countryCode, countryCode,
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata, numberToFill));
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata, numberToFill, true,
number));
assertEquals("Did not figure out CountryCodeSource correctly",
CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN, number.getCountryCodeSource());
} catch (NumberParseException e) { } catch (NumberParseException e) {
fail("Should not have thrown an exception: " + e.toString()); fail("Should not have thrown an exception: " + e.toString());
} }
number.clear();
try { try {
String phoneNumber = "2345-6789"; String phoneNumber = "2345-6789";
StringBuffer numberToFill = new StringBuffer(); StringBuffer numberToFill = new StringBuffer();
assertEquals("Should not have extracted a country code - no international prefix present.", assertEquals("Should not have extracted a country code - no international prefix present.",
0, 0,
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata, numberToFill));
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata, numberToFill, true,
number));
assertEquals("Did not figure out CountryCodeSource correctly",
CountryCodeSource.FROM_DEFAULT_COUNTRY, number.getCountryCodeSource());
} catch (NumberParseException e) { } catch (NumberParseException e) {
fail("Should not have thrown an exception: " + e.toString()); fail("Should not have thrown an exception: " + e.toString());
} }
number.clear();
try { try {
String phoneNumber = "0119991123456789"; String phoneNumber = "0119991123456789";
StringBuffer numberToFill = new StringBuffer(); StringBuffer numberToFill = new StringBuffer();
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata,
numberToFill);
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata, numberToFill, true, number);
fail("Should have thrown an exception, no valid country code present."); fail("Should have thrown an exception, no valid country code present.");
} catch (NumberParseException e) { } catch (NumberParseException e) {
// Expected. // Expected.
@ -1000,34 +1083,58 @@ public class PhoneNumberUtilTest extends TestCase {
NumberParseException.ErrorType.INVALID_COUNTRY_CODE, NumberParseException.ErrorType.INVALID_COUNTRY_CODE,
e.getErrorType()); e.getErrorType());
} }
number.clear();
try { try {
String phoneNumber = "(1 610) 619 4466"; String phoneNumber = "(1 610) 619 4466";
int countryCode = 1; int countryCode = 1;
StringBuffer numberToFill = new StringBuffer(); StringBuffer numberToFill = new StringBuffer();
assertEquals("Should have extracted the country code of the region passed in", assertEquals("Should have extracted the country code of the region passed in",
countryCode, countryCode,
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata, numberToFill));
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata, numberToFill, true,
number));
assertEquals("Did not figure out CountryCodeSource correctly",
CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN,
number.getCountryCodeSource());
} catch (NumberParseException e) { } catch (NumberParseException e) {
fail("Should not have thrown an exception: " + e.toString()); fail("Should not have thrown an exception: " + e.toString());
} }
number.clear();
try {
String phoneNumber = "(1 610) 619 4466";
int countryCode = 1;
StringBuffer numberToFill = new StringBuffer();
assertEquals("Should have extracted the country code of the region passed in",
countryCode,
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata, numberToFill, false,
number));
assertFalse("Should not contain CountryCodeSource.", number.hasCountryCodeSource());
} catch (NumberParseException e) {
fail("Should not have thrown an exception: " + e.toString());
}
number.clear();
try { try {
String phoneNumber = "(1 610) 619 446"; String phoneNumber = "(1 610) 619 446";
StringBuffer numberToFill = new StringBuffer(); StringBuffer numberToFill = new StringBuffer();
assertEquals("Should not have extracted a country code - invalid number after extraction " + assertEquals("Should not have extracted a country code - invalid number after extraction " +
"of uncertain country code.", "of uncertain country code.",
0, 0,
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata, numberToFill));
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata, numberToFill, false,
number));
assertFalse("Should not contain CountryCodeSource.", number.hasCountryCodeSource());
} catch (NumberParseException e) { } catch (NumberParseException e) {
fail("Should not have thrown an exception: " + e.toString()); fail("Should not have thrown an exception: " + e.toString());
} }
number.clear();
try { try {
String phoneNumber = "(1 610) 619 43 446"; String phoneNumber = "(1 610) 619 43 446";
StringBuffer numberToFill = new StringBuffer(); StringBuffer numberToFill = new StringBuffer();
assertEquals("Should not have extracted a country code - invalid number both before and " + assertEquals("Should not have extracted a country code - invalid number both before and " +
"after extraction of uncertain country code.", "after extraction of uncertain country code.",
0, 0,
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata,
numberToFill));
phoneUtil.maybeExtractCountryCode(phoneNumber, metadata, numberToFill, true,
number));
assertEquals("Did not figure out CountryCodeSource correctly",
CountryCodeSource.FROM_DEFAULT_COUNTRY, number.getCountryCodeSource());
} catch (NumberParseException e) { } catch (NumberParseException e) {
fail("Should not have thrown an exception: " + e.toString()); fail("Should not have thrown an exception: " + e.toString());
} }
@ -1341,15 +1448,37 @@ public class PhoneNumberUtilTest extends TestCase {
} }
public void testParseAndKeepRaw() throws Exception { public void testParseAndKeepRaw() throws Exception {
PhoneNumber alphaNumericNumber =
PhoneNumber alphaNumericNumber1 =
PhoneNumber.newBuilder().setCountryCode(1).setNationalNumber(180074935247L) PhoneNumber.newBuilder().setCountryCode(1).setNationalNumber(180074935247L)
.setRawInput("1800 six-flags").build();
assertEquals(alphaNumericNumber,
.setRawInput("1800 six-flags")
.setCountryCodeSource(CountryCodeSource.FROM_DEFAULT_COUNTRY).build();
assertEquals(alphaNumericNumber1,
phoneUtil.parseAndKeepRawInput("1800 six-flags", "US")); phoneUtil.parseAndKeepRawInput("1800 six-flags", "US"));
PhoneNumber alphaNumericNumber2 =
PhoneNumber.newBuilder().setCountryCode(1).setNationalNumber(8007493524L)
.setRawInput("1800 six-flag")
.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN).build();
assertEquals(alphaNumericNumber2,
phoneUtil.parseAndKeepRawInput("1800 six-flag", "US"));
PhoneNumber alphaNumericNumber3 =
PhoneNumber.newBuilder().setCountryCode(1).setNationalNumber(8007493524L)
.setRawInput("+1800 six-flag")
.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN).build();
assertEquals(alphaNumericNumber3,
phoneUtil.parseAndKeepRawInput("+1800 six-flag", "CN"));
PhoneNumber alphaNumericNumber4 =
PhoneNumber.newBuilder().setCountryCode(1).setNationalNumber(18007493524L)
.setRawInput("1800 six-flag")
.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITH_IDD).build();
assertEquals(alphaNumericNumber4,
phoneUtil.parseAndKeepRawInput("001800 six-flag", "NZ"));
} }
public void testCountryWithNoNumberDesc() { public void testCountryWithNoNumberDesc() {
// Andorra is a country where we don't have PhoneNumberDesc info in the meta data.
// Andorra is a country where we don't have PhoneNumberDesc info in the metadata.
PhoneNumber adNumber = PhoneNumber adNumber =
PhoneNumber.newBuilder().setCountryCode(376).setNationalNumber(12345L).build(); PhoneNumber.newBuilder().setCountryCode(376).setNationalNumber(12345L).build();
assertEquals("+376 12345", phoneUtil.format(adNumber, assertEquals("+376 12345", phoneUtil.format(adNumber,


Loading…
Cancel
Save