/** * Extracts the pattern for international format. If there is no intlFormat, default to using the * national format. If the intlFormat is set to "NA" the intlFormat should be ignored. * * @throws RuntimeException if multiple intlFormats have been encountered. * @return whether an international number format is defined. */ public static bool LoadInternationalFormat(PhoneMetadata.Builder metadata, XElement numberFormatElement, string nationalFormat) { var intlFormat = new NumberFormat.Builder(); SetLeadingDigitsPatterns(numberFormatElement, intlFormat); intlFormat.SetPattern(numberFormatElement.GetAttribute(PATTERN)); var intlFormatPattern = numberFormatElement.GetElementsByTagName(INTL_FORMAT).ToList(); var hasExplicitIntlFormatDefined = false; if (intlFormatPattern.Count > 1) { throw new Exception("Invalid number of intlFormat patterns for country: " + metadata.Id); } if (intlFormatPattern.Count == 0) { // Default to use the same as the national pattern if none is defined. intlFormat.SetFormat(nationalFormat); } else { var intlFormatPatternValue = intlFormatPattern.First().Value; intlFormat.SetFormat(intlFormatPatternValue); hasExplicitIntlFormatDefined = true; } if (intlFormat.HasFormat) { metadata.AddIntlNumberFormat(intlFormat); } return(hasExplicitIntlFormatDefined); }
/** * Extracts the pattern for international format. If there is no intlFormat, default to using the * national format. If the intlFormat is set to "NA" the intlFormat should be ignored. * * @throws RuntimeException if multiple intlFormats have been encountered. * @return whether an international number format is defined. */ // @VisibleForTesting public static bool LoadInternationalFormat(PhoneMetadata.Builder metadata, XElement numberFormatElement, String nationalFormat) { var intlFormat = new NumberFormat.Builder(); SetLeadingDigitsPatterns(numberFormatElement, intlFormat); intlFormat.SetPattern(numberFormatElement.GetAttribute(PATTERN)); var intlFormatPattern = numberFormatElement.GetElementsByTagName(INTL_FORMAT); bool hasExplicitIntlFormatDefined = false; if (intlFormatPattern.Length > 1) { //LOGGER.log(Level.SEVERE, // "A maximum of one intlFormat pattern for a numberFormat element should be " + // "defined."); throw new Exception("Invalid number of intlFormat patterns for country: " + metadata.Id); } if (intlFormatPattern.Length == 0) { // Default to use the same as the national pattern if none is defined. intlFormat.SetFormat(nationalFormat); } else { String intlFormatPatternValue = intlFormatPattern[0].Value; if (!intlFormatPatternValue.Equals("NA")) { intlFormat.SetFormat(intlFormatPatternValue); } hasExplicitIntlFormatDefined = true; } if (intlFormat.HasFormat) { metadata.AddIntlNumberFormat(intlFormat); } return(hasExplicitIntlFormatDefined); }
/** * Extracts the pattern for the national format. * * @throws RuntimeException if multiple or no formats have been encountered. * @return the national format string. */ public static string LoadNationalFormat(PhoneMetadata.Builder metadata, XElement numberFormatElement, NumberFormat.Builder format) { SetLeadingDigitsPatterns(numberFormatElement, format); format.SetPattern(ValidateRE(numberFormatElement.GetAttribute(PATTERN))); var formatPattern = numberFormatElement.GetElementsByTagName(FORMAT).ToList(); if (formatPattern.Count != 1) throw new Exception("Invalid number of format patterns for country: " + metadata.Id); var nationalFormat = formatPattern[0].Value; format.SetFormat(nationalFormat); return nationalFormat; }
/** * Extracts the pattern for the national format. * * @throws RuntimeException if multiple or no formats have been encountered. * @return the national format string. */ // @VisibleForTesting public static String LoadNationalFormat(PhoneMetadata.Builder metadata, XElement numberFormatElement, NumberFormat.Builder format) { SetLeadingDigitsPatterns(numberFormatElement, format); format.SetPattern(ValidateRE(numberFormatElement.GetAttribute(PATTERN))); var formatPattern = numberFormatElement.Elements(FORMAT).ToArray(); if (formatPattern.Count() != 1) { //LOGGER.log(Level.SEVERE, // "Only one format pattern for a numberFormat element should be defined."); throw new Exception("Invalid number of format patterns for country: " + metadata.Id); } String nationalFormat = formatPattern[0].Value; format.SetFormat(nationalFormat); return(nationalFormat); }
/** * Extracts the pattern for international format. If there is no intlFormat, default to using the * national format. If the intlFormat is set to "NA" the intlFormat should be ignored. * * @throws RuntimeException if multiple intlFormats have been encountered. * @return whether an international number format is defined. */ // @VisibleForTesting public static bool LoadInternationalFormat(PhoneMetadata.Builder metadata, XmlElement numberFormatElement, String nationalFormat) { NumberFormat.Builder intlFormat = new NumberFormat.Builder(); SetLeadingDigitsPatterns(numberFormatElement, intlFormat); intlFormat.SetPattern(numberFormatElement.GetAttribute(PATTERN)); var intlFormatPattern = numberFormatElement.GetElementsByTagName(INTL_FORMAT); bool hasExplicitIntlFormatDefined = false; if (intlFormatPattern.Count > 1) { //LOGGER.log(Level.SEVERE, // "A maximum of one intlFormat pattern for a numberFormat element should be " + // "defined."); throw new Exception("Invalid number of intlFormat patterns for country: " + metadata.Id); } else if (intlFormatPattern.Count == 0) { // Default to use the same as the national pattern if none is defined. intlFormat.SetFormat(nationalFormat); } else { String intlFormatPatternValue = intlFormatPattern[0].InnerText; if (!intlFormatPatternValue.Equals("NA")) { intlFormat.SetFormat(intlFormatPatternValue); } hasExplicitIntlFormatDefined = true; } if (intlFormat.HasFormat) { metadata.AddIntlNumberFormat(intlFormat); } return hasExplicitIntlFormatDefined; }
/** * Formats a phone number for out-of-country dialing purposes. * * Note that in this version, if the number was entered originally using alpha characters and * this version of the number is stored in raw_input, this representation of the number will be * used rather than the digit representation. Grouping information, as specified by characters * such as "-" and " ", will be retained. * * <p><b>Caveats:</b></p> * <ul> * <li> This will not produce good results if the country calling code is both present in the raw * input _and_ is the start of the national number. This is not a problem in the regions * which typically use alpha numbers. * <li> This will also not produce good results if the raw input has any grouping information * within the first three digits of the national number, and if the function needs to strip * preceding digits/words in the raw input before these digits. Normally people group the * first three digits together so this is not a huge problem - and will be fixed if it * proves to be so. * </ul> * * @param number the phone number that needs to be formatted * @param regionCallingFrom the region where the call is being placed * @return the formatted phone number */ public String FormatOutOfCountryKeepingAlphaChars(PhoneNumber number, String regionCallingFrom) { var rawInput = number.RawInput; // If there is no raw input, then we can't keep alpha characters because there aren't any. // In this case, we return formatOutOfCountryCallingNumber. if (rawInput.Length == 0) return FormatOutOfCountryCallingNumber(number, regionCallingFrom); int countryCode = number.CountryCode; if (!HasValidCountryCallingCode(countryCode)) return rawInput; // Strip any prefix such as country calling code, IDD, that was present. We do this by comparing // the number in raw_input with the parsed number. // To do this, first we normalize punctuation. We retain number grouping symbols such as " " // only. rawInput = NormalizeHelper(rawInput, ALL_PLUS_NUMBER_GROUPING_SYMBOLS, true); // Now we trim everything before the first three digits in the parsed number. We choose three // because all valid alpha numbers have 3 digits at the start - if it does not, then we don't // trim anything at all. Similarly, if the national number was less than three digits, we don't // trim anything at all. var nationalNumber = GetNationalSignificantNumber(number); if (nationalNumber.Length > 3) { int firstNationalNumberDigit = rawInput.IndexOf(nationalNumber.Substring(0, 3)); if (firstNationalNumberDigit != -1) rawInput = rawInput.Substring(firstNationalNumberDigit); } var metadataForRegionCallingFrom = GetMetadataForRegion(regionCallingFrom); if (countryCode == NANPA_COUNTRY_CODE) { if (IsNANPACountry(regionCallingFrom)) return countryCode + " " + rawInput; } else if (IsValidRegionCode(regionCallingFrom) && countryCode == GetCountryCodeForValidRegion(regionCallingFrom)) { NumberFormat formattingPattern = ChooseFormattingPatternForNumber(metadataForRegionCallingFrom.NumberFormatList, nationalNumber); if (formattingPattern == null) // If no pattern above is matched, we format the original input. return rawInput; var newFormat = new NumberFormat.Builder(); newFormat.MergeFrom(formattingPattern); // The first group is the first group of digits that the user wrote together. newFormat.SetPattern("(\\d+)(.*)"); // Here we just concatenate them back together after the national prefix has been fixed. newFormat.SetFormat("$1$2"); // Now we format using this pattern instead of the default pattern, but with the national // prefix prefixed if necessary. // This will not work in the cases where the pattern (and not the leading digits) decide // whether a national prefix needs to be used, since we have overridden the pattern to match // anything, but that is not the case in the metadata to date. return FormatNsnUsingPattern(rawInput, newFormat.Build(), PhoneNumberFormat.NATIONAL); } String internationalPrefixForFormatting = ""; // If an unsupported region-calling-from is entered, or a country with multiple international // prefixes, the international format of the number is returned, unless there is a preferred // international prefix. if (metadataForRegionCallingFrom != null) { String internationalPrefix = metadataForRegionCallingFrom.InternationalPrefix; internationalPrefixForFormatting = UNIQUE_INTERNATIONAL_PREFIX.MatchAll(internationalPrefix).Success ? internationalPrefix : metadataForRegionCallingFrom.PreferredInternationalPrefix; } var formattedNumber = new StringBuilder(rawInput); String regionCode = GetRegionCodeForCountryCode(countryCode); PhoneMetadata metadataForRegion = GetMetadataForRegionOrCallingCode(countryCode, regionCode); MaybeAppendFormattedExtension(number, metadataForRegion, PhoneNumberFormat.INTERNATIONAL, formattedNumber); if (internationalPrefixForFormatting.Length > 0) { formattedNumber.Insert(0, " ").Insert(0, countryCode).Insert(0, " ") .Insert(0, internationalPrefixForFormatting); } else { // Invalid region entered as country-calling-from (so no metadata was found for it) or the // region chosen has multiple international dialling prefixes. // LOGGER.log(Level.WARNING, // "Trying to format number from invalid region " // + regionCallingFrom // + ". International formatting applied."); PrefixNumberWithCountryCallingCode(countryCode, PhoneNumberFormat.INTERNATIONAL, formattedNumber); } return formattedNumber.ToString(); }
/** * Formats a phone number for out-of-country dialing purposes. * * Note that in this version, if the number was entered originally using alpha characters and * this version of the number is stored in raw_input, this representation of the number will be * used rather than the digit representation. Grouping information, as specified by characters * such as "-" and " ", will be retained. * * <p><b>Caveats:</b></p> * <ul> * <li> This will not produce good results if the country calling code is both present in the raw * input _and_ is the start of the national number. This is not a problem in the regions * which typically use alpha numbers. * <li> This will also not produce good results if the raw input has any grouping information * within the first three digits of the national number, and if the function needs to strip * preceding digits/words in the raw input before these digits. Normally people group the * first three digits together so this is not a huge problem - and will be fixed if it * proves to be so. * </ul> * * @param number the phone number that needs to be formatted * @param regionCallingFrom the region where the call is being placed * @return the formatted phone number */ public String FormatOutOfCountryKeepingAlphaChars(PhoneNumber number, String regionCallingFrom) { var rawInput = number.RawInput; // If there is no raw input, then we can't keep alpha characters because there aren't any. // In this case, we return formatOutOfCountryCallingNumber. if (rawInput.Length == 0) return FormatOutOfCountryCallingNumber(number, regionCallingFrom); int countryCode = number.CountryCode; var regionCode = GetRegionCodeForCountryCode(countryCode); if (!HasValidRegionCode(regionCode, countryCode, rawInput)) return rawInput; // Strip any prefix such as country calling code, IDD, that was present. We do this by comparing // the number in raw_input with the parsed number. // To do this, first we normalize punctuation. We retain number grouping symbols such as " " // only. rawInput = NormalizeHelper(rawInput, ALL_PLUS_NUMBER_GROUPING_SYMBOLS, true); // Now we trim everything before the first three digits in the parsed number. We choose three // because all valid alpha numbers have 3 digits at the start - if it does not, then we don't // trim anything at all. Similarly, if the national number was less than three digits, we don't // trim anything at all. var nationalNumber = GetNationalSignificantNumber(number); if (nationalNumber.Length > 3) { int firstNationalNumberDigit = rawInput.IndexOf(nationalNumber.Substring(0, 3)); if (firstNationalNumberDigit != -1) rawInput = rawInput.Substring(firstNationalNumberDigit); } var metadata = GetMetadataForRegion(regionCallingFrom); if (countryCode == NANPA_COUNTRY_CODE) { if (IsNANPACountry(regionCallingFrom)) return countryCode + " " + rawInput; } else if (countryCode == GetCountryCodeForRegion(regionCallingFrom)) { // Here we copy the formatting rules so we can modify the pattern we expect to match against. var availableFormats = new List<NumberFormat>(metadata.NumberFormatCount); foreach (var format in metadata.NumberFormatList) { var newFormat = new NumberFormat.Builder(); newFormat.MergeFrom(format); // The first group is the first group of digits that the user determined. newFormat.SetPattern("(\\d+)(.*)"); // Here we just concatenate them back together after the national prefix has been fixed. newFormat.SetFormat("$1$2"); availableFormats.Add(newFormat.Build()); } // Now we format using these patterns instead of the default pattern, but with the national // prefix prefixed if necessary, by choosing the format rule based on the leading digits // present in the unformatted national number. // This will not work in the cases where the pattern (and not the leading digits) decide // whether a national prefix needs to be used, since we have overridden the pattern to match // anything, but that is not the case in the metadata to date. return FormatAccordingToFormats(rawInput, availableFormats, PhoneNumberFormat.NATIONAL); } var internationalPrefix = metadata.InternationalPrefix; // For countries that have multiple international prefixes, the international format of the // number is returned, unless there is a preferred international prefix. String internationalPrefixForFormatting = UNIQUE_INTERNATIONAL_PREFIX.MatchAll(internationalPrefix).Success ? internationalPrefix : metadata.PreferredInternationalPrefix; var formattedNumber = new StringBuilder(rawInput); MaybeGetFormattedExtension(number, regionCode, PhoneNumberFormat.INTERNATIONAL, formattedNumber); if (internationalPrefixForFormatting.Length > 0) { formattedNumber.Insert(0, " ").Insert(0, countryCode.ToString(CultureInfo.InvariantCulture)).Insert(0, " ") .Insert(0, internationalPrefixForFormatting); } else { FormatNumberByFormat(countryCode, PhoneNumberFormat.INTERNATIONAL, formattedNumber); } return formattedNumber.ToString(); }