/** * Helper method to get the national-number part of a number, formatted without any national * prefix, and return it as a set of digit blocks that would be formatted together. */ private static String[] GetNationalNumberGroups(PhoneNumberUtil util, PhoneNumber number, NumberFormat formattingPattern) { if (formattingPattern == null) { // This will be in the format +CC-DG;ext=EXT where DG represents groups of digits. String rfc3966Format = util.Format(number, PhoneNumberFormat.RFC3966); // We remove the extension part from the formatted string before splitting it into different // groups. int endIndex = rfc3966Format.IndexOf(';'); if (endIndex < 0) { endIndex = rfc3966Format.Length; } // The country-code will have a '-' following it. int startIndex = rfc3966Format.IndexOf('-') + 1; return(rfc3966Format.Substring(startIndex, endIndex - startIndex).Split(new [] { '-' })); } else { // We format the NSN only, and split that according to the separator. String nationalSignificantNumber = util.GetNationalSignificantNumber(number); return(util.FormatNsnUsingPattern(nationalSignificantNumber, formattingPattern, PhoneNumberFormat.RFC3966).Split(new [] { '-' })); } }
/// <summary> /// Helper method to get the national-number part of a number, formatted without any national /// prefix, and return it as a set of digit blocks that should be formatted together according to /// the formatting pattern passed in. /// </summary> private static IList <string> GetNationalNumberGroups(PhoneNumberUtil util, PhoneNumber number, NumberFormat formattingPattern) { // If a format is provided, we format the NSN only, and split that according to the separator. var nationalSignificantNumber = util.GetNationalSignificantNumber(number); return(util.FormatNsnUsingPattern(nationalSignificantNumber, formattingPattern, PhoneNumberFormat.RFC3966).Split('-')); }
/// <summary> /// Extracts the subscriber number /// </summary> /// <param name="parser">An instance of type <see cref="PhoneNumberUtil"/> to parse</param> /// <param name="parsedNumber">An instance of type <see cref="PhoneNumber"/> representing the parsed number</param> /// <returns>The subscriber number as <see cref="string"/></returns> private string GetSubscriberNumber(PhoneNumberUtil parser, PhoneNumber parsedNumber) { // Get the national relevant number and the length of the area code string nationalNumber = parser.GetNationalSignificantNumber(parsedNumber); int areaCodeLength = parser.GetLengthOfGeographicalAreaCode(parsedNumber); // Get the substring of the national relevant number from the index of the length of the area code string subscriberNumber = nationalNumber.Substring(areaCodeLength); return(subscriberNumber); }
public static bool IsNationalPrefixPresentIfRequired(PhoneNumber number, PhoneNumberUtil util) { // First, check how we deduced the country code. If it was written in international format, then // the national prefix is not required. if (number.CountryCodeSource != PhoneNumber.Types.CountryCodeSource.FROM_DEFAULT_COUNTRY) { return(true); } String phoneNumberRegion = util.GetRegionCodeForCountryCode(number.CountryCode); PhoneMetadata metadata = util.GetMetadataForRegion(phoneNumberRegion); if (metadata == null) { return(true); } // Check if a national prefix should be present when formatting this number. String nationalNumber = util.GetNationalSignificantNumber(number); NumberFormat formatRule = util.ChooseFormattingPatternForNumber(metadata.NumberFormatList, nationalNumber); // To do this, we check that a national prefix formatting rule was present and that it wasn't // just the first-group symbol ($1) with punctuation. if ((formatRule != null) && formatRule.NationalPrefixFormattingRule.Length > 0) { if (formatRule.NationalPrefixOptionalWhenFormatting) { // The national-prefix is optional in these cases, so we don't need to check if it was // present. return(true); } // Remove the first-group symbol. String candidateNationalPrefixRule = formatRule.NationalPrefixFormattingRule; // We assume that the first-group symbol will never be _before_ the national prefix. candidateNationalPrefixRule = candidateNationalPrefixRule.Substring(0, candidateNationalPrefixRule.IndexOf("${1}")); candidateNationalPrefixRule = PhoneNumberUtil.NormalizeDigitsOnly(candidateNationalPrefixRule); if (candidateNationalPrefixRule.Length == 0) { // National Prefix not needed for this number. return(true); } // Normalize the remainder. String rawInputCopy = PhoneNumberUtil.NormalizeDigitsOnly(number.RawInput); StringBuilder rawInput = new StringBuilder(rawInputCopy); // Check if we found a national prefix and/or carrier code at the start of the raw input, and // return the result. return(util.MaybeStripNationalPrefixAndCarrierCode(rawInput, metadata, null)); } return(true); }
public bool CheckNumberGroupingIsValid( PhoneNumber number, string candidate, PhoneNumberUtil util, CheckGroups checker) { // TODO: Evaluate how this works for other locales (testing has been limited to NANPA regions) // and optimise if necessary. var normalizedCandidate = PhoneNumberUtil.NormalizeDigits(new StringBuilder(candidate), true /* keep non-digits */); var formattedNumberGroups = GetNationalNumberGroups(util, number); if (checker(util, number, normalizedCandidate, formattedNumberGroups)) { return(true); } // If this didn't pass, see if there are any alternate formats that match, and try them instead. var alternateFormats = MetadataManager.GetAlternateFormatsForCountry(number.CountryCode); var nationalSignificantNumber = util.GetNationalSignificantNumber(number); if (alternateFormats != null) { foreach (var alternateFormat in alternateFormats.NumberFormatList) { if (alternateFormat.LeadingDigitsPatternCount > 0) { // There is only one leading digits pattern for alternate formats. var pattern = regexCache.GetPatternForRegex(alternateFormat.GetLeadingDigitsPattern(0)); if (!pattern.IsMatchBeginning(nationalSignificantNumber)) { // Leading digits don't match; try another one. continue; } } formattedNumberGroups = GetNationalNumberGroups(util, number, alternateFormat); if (checker(util, number, normalizedCandidate, formattedNumberGroups)) { return(true); } } } return(false); }
public static bool AllNumberGroupsRemainGrouped(PhoneNumberUtil util, PhoneNumber number, StringBuilder normalizedCandidate, String[] formattedNumberGroups) { int fromIndex = 0; // Check each group of consecutive digits are not broken into separate groupings in the // {@code normalizedCandidate} string. for (int i = 0; i < formattedNumberGroups.Length; i++) { // Fails if the substring of {@code normalizedCandidate} starting from {@code fromIndex} // doesn't contain the consecutive digits in formattedNumberGroups[i]. fromIndex = normalizedCandidate.ToString().IndexOf(formattedNumberGroups[i], fromIndex); if (fromIndex < 0) { return(false); } // Moves {@code fromIndex} forward. fromIndex += formattedNumberGroups[i].Length; if (i == 0 && fromIndex < normalizedCandidate.Length) { // We are at the position right after the NDC. if (char.IsDigit(normalizedCandidate[fromIndex])) { // This means there is no formatting symbol after the NDC. In this case, we only // accept the number if there is no formatting symbol at all in the number, except // for extensions. String nationalSignificantNumber = util.GetNationalSignificantNumber(number); return(normalizedCandidate.ToString().Substring(fromIndex - formattedNumberGroups[i].Length) .StartsWith(nationalSignificantNumber)); } } } // The check here makes sure that we haven't mistakenly already used the extension to // match the last group of the subscriber number. Note the extension cannot have // formatting in-between digits. return(normalizedCandidate.ToString().Substring(fromIndex).Contains(number.Extension)); }
/** * Returns the description of the geographical area the {@code number} corresponds to. This method * distinguishes the case of an invalid prefix and a prefix for which the name is not available in * the current language. If the description is not available in the current language an empty * string is returned. If no description was found for the provided number, null is returned. * * @param number the phone number to look up * @return the description of the geographical area */ public String Lookup(PhoneNumber number) { int numOfEntries = areaCodeMapStorage.getNumOfEntries(); if (numOfEntries == 0) { return(null); } long phonePrefix = long.Parse(number.CountryCode + phoneUtil.GetNationalSignificantNumber(number)); int currentIndex = numOfEntries - 1; List <int> currentSetOfLengths = areaCodeMapStorage.getPossibleLengths(); var length = currentSetOfLengths.Count; while (length > 0) { int possibleLength = currentSetOfLengths[length - 1]; String phonePrefixStr = phonePrefix.ToString(); if (phonePrefixStr.Length > possibleLength) { phonePrefix = long.Parse(phonePrefixStr.Substring(0, possibleLength)); } currentIndex = binarySearch(0, currentIndex, phonePrefix); if (currentIndex < 0) { return(null); } int currentPrefix = areaCodeMapStorage.getPrefix(currentIndex); if (phonePrefix == currentPrefix) { return(areaCodeMapStorage.getDescription(currentIndex)); } while (length > 0 && currentSetOfLengths[length - 1] >= possibleLength) { length--; } } return(null); }
/// <summary> /// Retrieves the area code of parsed number /// </summary> /// <param name="parser">An instance of type <see cref="PhoneNumberUtil"/> representing the parser</param> /// <param name="parsedNumber">An instance of type <see cref="PhoneNumber"/> representing the parsed number</param> /// <param name="number">The raw number as <see cref="string"/></param> /// <returns></returns> private string GetAreaCode(PhoneNumberUtil parser, PhoneNumber parsedNumber, string number) { string areaCode; // Get length of area code and the national relevant part of the number int areaCodeLength = parser.GetLengthOfGeographicalAreaCode(parsedNumber); string nationalNumber = parser.GetNationalSignificantNumber(parsedNumber); // Check if the number starts with "0" if (number.StartsWith("0")) { // Get the area code which starts with a "0" areaCode = $"0{nationalNumber.Substring(0, areaCodeLength)}"; } else { // Get the area code which does not start with a "0" areaCode = nationalNumber.Substring(0, areaCodeLength); } return(areaCode); }
public static bool AllNumberGroupsAreExactlyPresent(PhoneNumberUtil util, PhoneNumber number, StringBuilder normalizedCandidate, String[] formattedNumberGroups) { String[] candidateGroups = PhoneNumberUtil.NON_DIGITS_PATTERN.Split(normalizedCandidate.ToString()); // Set this to the last group, skipping it if the number has an extension. int candidateNumberGroupIndex = number.HasExtension ? candidateGroups.Length - 2 : candidateGroups.Length - 1; // First we check if the national significant number is formatted as a block. // We use contains and not equals, since the national significant number may be present with // a prefix such as a national number prefix, or the country code itself. if (candidateGroups.Length == 1 || candidateGroups[candidateNumberGroupIndex].Contains( util.GetNationalSignificantNumber(number))) { return(true); } // Starting from the end, go through in reverse, excluding the first group, and check the // candidate and number groups are the same. for (int formattedNumberGroupIndex = (formattedNumberGroups.Length - 1); formattedNumberGroupIndex > 0 && candidateNumberGroupIndex >= 0; formattedNumberGroupIndex--, candidateNumberGroupIndex--) { if (!candidateGroups[candidateNumberGroupIndex].Equals( formattedNumberGroups[formattedNumberGroupIndex])) { return(false); } } // Now check the first group. There may be a national prefix at the start, so we only check // that the candidate group ends with the formatted number group. return(candidateNumberGroupIndex >= 0 && candidateGroups[candidateNumberGroupIndex].EndsWith(formattedNumberGroups[0])); }