/** * Parses a string and returns it in proto buffer format. This method differs from {@link #parse} * in that 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 * such as +, ( and -, as well as a phone number extension. * @param defaultRegion region that we are expecting the number to be from. This is only used * if the number being parsed is not written in international format. * The country calling code for the number in this case would be stored * as that of the default region supplied. * @return a phone number proto buffer filled with the parsed number * @throws NumberParseException if the string is not considered to be a viable phone number or if * no default region was supplied */ public PhoneNumber ParseAndKeepRawInput(String numberToParse, String defaultRegion) { var phoneNumber = new PhoneNumber.Builder(); ParseAndKeepRawInput(numberToParse, defaultRegion, phoneNumber); return phoneNumber.Build(); }
/** * Takes two phone numbers as strings and compares them for equality. This is a convenience * wrapper for {@link #isNumberMatch(PhoneNumber, PhoneNumber)}. No default region is known. * * @param firstNumber first number to compare. Can contain formatting, and can have country * calling code specified with + at the start. * @param secondNumber second number to compare. Can contain formatting, and can have country * calling code specified with + at the start. * @return NOT_A_NUMBER, NO_MATCH, SHORT_NSN_MATCH, NSN_MATCH, EXACT_MATCH. See * {@link #isNumberMatch(PhoneNumber, PhoneNumber)} for more details. */ public MatchType IsNumberMatch(String firstNumber, String secondNumber) { try { PhoneNumber firstNumberAsProto = Parse(firstNumber, UNKNOWN_REGION); return IsNumberMatch(firstNumberAsProto, secondNumber); } catch (NumberParseException e) { if (e.ErrorType == ErrorType.INVALID_COUNTRY_CODE) { try { PhoneNumber secondNumberAsProto = Parse(secondNumber, UNKNOWN_REGION); return IsNumberMatch(secondNumberAsProto, firstNumber); } catch (NumberParseException e2) { if (e2.ErrorType == ErrorType.INVALID_COUNTRY_CODE) { try { var firstNumberProto = new PhoneNumber.Builder(); var secondNumberProto = new PhoneNumber.Builder(); ParseHelper(firstNumber, null, false, false, firstNumberProto); ParseHelper(secondNumber, null, false, false, secondNumberProto); return IsNumberMatch(firstNumberProto.Build(), secondNumberProto.Build()); } catch (NumberParseException) { // Fall through and return MatchType.NOT_A_NUMBER. } } } } } // One or more of the phone numbers we are trying to match is not a viable phone number. return MatchType.NOT_A_NUMBER; }
/** * Takes two phone numbers and compares them for equality. This is a convenience wrapper for * {@link #isNumberMatch(PhoneNumber, PhoneNumber)}. No default region is known. * * @param firstNumber first number to compare in proto buffer format. * @param secondNumber second number to compare. Can contain formatting, and can have country * calling code specified with + at the start. * @return NOT_A_NUMBER, NO_MATCH, SHORT_NSN_MATCH, NSN_MATCH, EXACT_MATCH. See * {@link #isNumberMatch(PhoneNumber, PhoneNumber)} for more details. */ public MatchType IsNumberMatch(PhoneNumber firstNumber, String secondNumber) { // First see if the second number has an implicit country calling code, by attempting to parse // it. try { PhoneNumber secondNumberAsProto = Parse(secondNumber, UNKNOWN_REGION); return IsNumberMatch(firstNumber, secondNumberAsProto); } catch (NumberParseException e) { if (e.ErrorType == ErrorType.INVALID_COUNTRY_CODE) { // The second number has no country calling code. EXACT_MATCH is no longer possible. // We parse it as if the region was the same as that for the first number, and if // EXACT_MATCH is returned, we replace this with NSN_MATCH. String firstNumberRegion = GetRegionCodeForCountryCode(firstNumber.CountryCode); try { if (!firstNumberRegion.Equals(UNKNOWN_REGION)) { PhoneNumber secondNumberWithFirstNumberRegion = Parse(secondNumber, firstNumberRegion); MatchType match = IsNumberMatch(firstNumber, secondNumberWithFirstNumberRegion); if (match == MatchType.EXACT_MATCH) return MatchType.NSN_MATCH; return match; } else { // If the first number didn't have a valid country calling code, then we parse the // second number without one as well. var secondNumberProto = new PhoneNumber.Builder(); ParseHelper(secondNumber, null, false, false, secondNumberProto); return IsNumberMatch(firstNumber, secondNumberProto.Build()); } } catch (NumberParseException) { // Fall-through to return NOT_A_NUMBER. } } } // One or more of the phone numbers we are trying to match is not a viable phone number. return MatchType.NOT_A_NUMBER; }
/** * Gets the length of the national destination code (NDC) from the PhoneNumber object passed in, * so that clients could use it to split a national significant number into NDC and subscriber * number. The NDC of a phone number is normally the first group of digit(s) right after the * country calling code when the number is formatted in the international format, if there is a * subscriber number part that follows. An example of how this could be used: * * <pre> * PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); * PhoneNumber number = phoneUtil.parse("18002530000", "US"); * String nationalSignificantNumber = phoneUtil.getNationalSignificantNumber(number); * String nationalDestinationCode; * String subscriberNumber; * * int nationalDestinationCodeLength = phoneUtil.getLengthOfNationalDestinationCode(number); * if (nationalDestinationCodeLength > 0) { * nationalDestinationCode = nationalSignificantNumber.substring(0, * nationalDestinationCodeLength); * subscriberNumber = nationalSignificantNumber.substring(nationalDestinationCodeLength); * } else { * nationalDestinationCode = ""; * subscriberNumber = nationalSignificantNumber; * } * </pre> * * Refer to the unittests to see the difference between this function and * {@link #getLengthOfGeographicalAreaCode}. * * @param number the PhoneNumber object for which clients want to know the length of the NDC. * @return the length of NDC of the PhoneNumber object passed in. */ public int GetLengthOfNationalDestinationCode(PhoneNumber number) { 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. var builder = new PhoneNumber.Builder(); builder.MergeFrom(number); builder.ClearExtension(); copiedProto = builder.Build(); } else { copiedProto = number; } var nationalSignificantNumber = Format(copiedProto, PhoneNumberFormat.INTERNATIONAL); var numberGroups = NON_DIGITS_PATTERN.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 calling code. The third // group will be area code if it is not the last group. if (numberGroups.Length <= 3) return 0; if (GetRegionCodeForCountryCode(number.CountryCode) == "AR" && GetNumberType(number) == PhoneNumberType.MOBILE) // Argentinian mobile numbers, when formatted in the international format, are in the form of // +54 9 NDC XXXX.... As a result, we take the length of the third group (NDC) and add 1 for // the digit 9, which also forms part of the national significant number. // // TODO: Investigate the possibility of better modeling the metadata to make it // easier to obtain the NDC. return numberGroups[3].Length + 1; return numberGroups[2].Length; }