public Builder Clear() { result = new PhoneMetadata(); return this; }
/** * Extracts the country calling code from the beginning of nationalNumber to * prefixBeforeNationalNumber when they are available, and places the remaining input into * nationalNumber. * * @return true when a valid country calling code can be found. */ private bool AttemptToExtractCountryCallingCode() { if (nationalNumber.Length == 0) { return false; } StringBuilder numberWithoutCountryCallingCode = new StringBuilder(); int countryCode = phoneUtil.ExtractCountryCode(nationalNumber, numberWithoutCountryCallingCode); if (countryCode == 0) { return false; } nationalNumber.Length = 0; nationalNumber.Append(numberWithoutCountryCallingCode); String newRegionCode = phoneUtil.GetRegionCodeForCountryCode(countryCode); if (PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY.Equals(newRegionCode)) { currentMetaData = phoneUtil.GetMetadataForNonGeographicalRegion(countryCode); } else if (!newRegionCode.Equals(defaultCountry)) { currentMetaData = GetMetadataForRegion(newRegionCode); } String countryCodeString = countryCode.ToString(); prefixBeforeNationalNumber.Append(countryCodeString).Append(" "); return true; }
public PhoneMetadata BuildPartial() { if (result == null) { throw new global::System.InvalidOperationException("build() has already been called on this Builder"); } PhoneMetadata returnMe = result; result = null; return returnMe; }
/** * Constructs an as-you-type formatter. Should be obtained from {@link * PhoneNumberUtil#getAsYouTypeFormatter}. * * @param regionCode the country/region where the phone number is being entered */ public AsYouTypeFormatter(String regionCode) { digitPattern = new Regex(digitPlaceholder, RegexOptions.Compiled); defaultCountry = regionCode; currentMetaData = GetMetadataForRegion(defaultCountry); defaultMetaData = currentMetaData; }
/** * Clears the internal state of the formatter, so it can be reused. */ public void Clear() { currentOutput = ""; accruedInput.Length = 0; accruedInputWithoutFormatting.Length = 0; formattingTemplate.Length = 0; lastMatchPosition = 0; currentFormattingPattern = ""; prefixBeforeNationalNumber.Length = 0; nationalPrefixExtracted = ""; nationalNumber.Length = 0; ableToFormat = true; inputHasFormatting = false; positionToRemember = 0; originalPosition = 0; isInternationalFormatting = false; isExpectingCountryCallingCode = false; possibleFormats.Clear(); if (!currentMetaData.Equals(defaultMetaData)) { currentMetaData = GetMetadataForRegion(defaultCountry); } }
/** * Strips any national prefix (such as 0, 1) present in the number provided. * * @param number the normalized telephone number that we wish to strip any national * dialing prefix from * @param metadata the metadata for the region that we think this number is from * @param carrierCode a place to insert the carrier code if one is extracted * @return true if a national prefix or carrier code (or both) could be extracted. */ public bool MaybeStripNationalPrefixAndCarrierCode( StringBuilder number, PhoneMetadata metadata, StringBuilder carrierCode) { int numberLength = number.Length; String possibleNationalPrefix = metadata.NationalPrefixForParsing; if (numberLength == 0 || possibleNationalPrefix.Length == 0) { // Early return for numbers of zero length. return false; } // Attempt to parse the first digits as a national prefix. var prefixMatcher = regexCache.GetPatternForRegex(possibleNationalPrefix); var prefixMatch = prefixMatcher.MatchBeginning(number.ToString()); //XXX: ToString if (prefixMatch.Success) { var nationalNumberRule = regexCache.GetPatternForRegex(metadata.GeneralDesc.NationalNumberPattern); // Check if the original number is viable. bool isViableOriginalNumber = nationalNumberRule.MatchAll(number.ToString()).Success; // prefixMatcher.group(numOfGroups) == null implies nothing was captured by the capturing // groups in possibleNationalPrefix; therefore, no transformation is necessary, and we just // remove the national prefix. int numOfGroups = prefixMatch.Groups.Count; String transformRule = metadata.NationalPrefixTransformRule; if (transformRule == null || transformRule.Length == 0 || !prefixMatch.Groups[numOfGroups - 1].Success) { // If the original number was viable, and the resultant number is not, we return. if (isViableOriginalNumber && !nationalNumberRule.MatchAll(number.ToString().Substring(prefixMatch.Index + prefixMatch.Length)).Success) return false; if (carrierCode != null && numOfGroups > 1 && prefixMatch.Groups[numOfGroups - 1].Success) carrierCode.Append(prefixMatch.Groups[1].Value); number.Remove(0, prefixMatch.Index + prefixMatch.Length); return true; } else { // Check that the resultant number is still viable. If not, return. Check this by copying // the string buffer and making the transformation on the copy first. StringBuilder transformedNumber = new StringBuilder( prefixMatcher.Replace(number.ToString(), transformRule, 1)); //XXX: ToString if (isViableOriginalNumber && !nationalNumberRule.MatchAll(transformedNumber.ToString()).Success) return false; if (carrierCode != null && numOfGroups > 2) carrierCode.Append(prefixMatcher.Match(number.ToString()).Groups[1].Value); number.Length = 0; number.Append(transformedNumber.ToString()); return true; } } return false; }
/** * 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, XmlElement numberFormatElement, NumberFormat.Builder format) { SetLeadingDigitsPatterns(numberFormatElement, format); format.SetPattern(ValidateRE(numberFormatElement.GetAttribute(PATTERN))); var formatPattern = numberFormatElement.GetElementsByTagName(FORMAT); 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].InnerText; format.SetFormat(nationalFormat); return nationalFormat; }
/** * Extracts the available formats from the provided DOM element. If it does not contain any * nationalPrefixFormattingRule, the one passed-in is retained. The nationalPrefix, * nationalPrefixFormattingRule and nationalPrefixOptionalWhenFormatting values are provided from * the parent (territory) element. */ // @VisibleForTesting public static void LoadAvailableFormats(PhoneMetadata.Builder metadata, XmlElement element, String nationalPrefix, String nationalPrefixFormattingRule, bool nationalPrefixOptionalWhenFormatting) { String carrierCodeFormattingRule = ""; if (element.HasAttribute(CARRIER_CODE_FORMATTING_RULE)) { carrierCodeFormattingRule = ValidateRE( GetDomesticCarrierCodeFormattingRuleFromElement(element, nationalPrefix)); } var numberFormatElements = element.GetElementsByTagName(NUMBER_FORMAT); bool hasExplicitIntlFormatDefined = false; int numOfFormatElements = numberFormatElements.Count; if (numOfFormatElements > 0) { foreach (XmlElement numberFormatElement in numberFormatElements) { var format = new NumberFormat.Builder(); if (numberFormatElement.HasAttribute(NATIONAL_PREFIX_FORMATTING_RULE)) { format.SetNationalPrefixFormattingRule( GetNationalPrefixFormattingRuleFromElement(numberFormatElement, nationalPrefix)); format.SetNationalPrefixOptionalWhenFormatting( numberFormatElement.HasAttribute(NATIONAL_PREFIX_OPTIONAL_WHEN_FORMATTING)); } else { format.SetNationalPrefixFormattingRule(nationalPrefixFormattingRule); format.SetNationalPrefixOptionalWhenFormatting(nationalPrefixOptionalWhenFormatting); } if (numberFormatElement.HasAttribute("carrierCodeFormattingRule")) { format.SetDomesticCarrierCodeFormattingRule(ValidateRE( GetDomesticCarrierCodeFormattingRuleFromElement( numberFormatElement, nationalPrefix))); } else { format.SetDomesticCarrierCodeFormattingRule(carrierCodeFormattingRule); } // Extract the pattern for the national format. String nationalFormat = LoadNationalFormat(metadata, numberFormatElement, format); metadata.AddNumberFormat(format); if (LoadInternationalFormat(metadata, numberFormatElement, nationalFormat)) { hasExplicitIntlFormatDefined = true; } } // Only a small number of regions need to specify the intlFormats in the xml. For the majority // of countries the intlNumberFormat metadata is an exact copy of the national NumberFormat // metadata. To minimize the size of the metadata file, we only keep intlNumberFormats that // actually differ in some way to the national formats. if (!hasExplicitIntlFormatDefined) { metadata.ClearIntlNumberFormat(); } } }
// @VisibleForTesting public static void LoadGeneralDesc(PhoneMetadata.Builder metadata, XmlElement element, bool liteBuild) { var generalDesc = ProcessPhoneNumberDescElement(null, element, GENERAL_DESC, liteBuild); metadata.SetGeneralDesc(generalDesc); metadata.SetFixedLine(ProcessPhoneNumberDescElement(generalDesc, element, FIXED_LINE, liteBuild)); metadata.SetMobile(ProcessPhoneNumberDescElement(generalDesc, element, MOBILE, liteBuild)); metadata.SetTollFree(ProcessPhoneNumberDescElement(generalDesc, element, TOLL_FREE, liteBuild)); metadata.SetPremiumRate(ProcessPhoneNumberDescElement(generalDesc, element, PREMIUM_RATE, liteBuild)); metadata.SetSharedCost(ProcessPhoneNumberDescElement(generalDesc, element, SHARED_COST, liteBuild)); metadata.SetVoip(ProcessPhoneNumberDescElement(generalDesc, element, VOIP, liteBuild)); metadata.SetPersonalNumber(ProcessPhoneNumberDescElement(generalDesc, element, PERSONAL_NUMBER, liteBuild)); metadata.SetPager(ProcessPhoneNumberDescElement(generalDesc, element, PAGER, liteBuild)); metadata.SetUan(ProcessPhoneNumberDescElement(generalDesc, element, UAN, liteBuild)); metadata.SetVoicemail(ProcessPhoneNumberDescElement(generalDesc, element, VOICEMAIL, liteBuild)); metadata.SetEmergency(ProcessPhoneNumberDescElement(generalDesc, element, EMERGENCY, liteBuild)); metadata.SetNoInternationalDialling(ProcessPhoneNumberDescElement(generalDesc, element, NO_INTERNATIONAL_DIALLING, liteBuild)); metadata.SetSameMobileAndFixedLinePattern( metadata.Mobile.NationalNumberPattern.Equals( metadata.FixedLine.NationalNumberPattern)); }
private PhoneNumberType GetNumberTypeHelper(String nationalNumber, PhoneMetadata metadata) { var generalNumberDesc = metadata.GeneralDesc; if (!generalNumberDesc.HasNationalNumberPattern || !IsNumberMatchingDesc(nationalNumber, generalNumberDesc)) return PhoneNumberType.UNKNOWN; if (IsNumberMatchingDesc(nationalNumber, metadata.PremiumRate)) return PhoneNumberType.PREMIUM_RATE; if (IsNumberMatchingDesc(nationalNumber, metadata.TollFree)) return PhoneNumberType.TOLL_FREE; if (IsNumberMatchingDesc(nationalNumber, metadata.SharedCost)) return PhoneNumberType.SHARED_COST; if (IsNumberMatchingDesc(nationalNumber, metadata.Voip)) return PhoneNumberType.VOIP; if (IsNumberMatchingDesc(nationalNumber, metadata.PersonalNumber)) return PhoneNumberType.PERSONAL_NUMBER; if (IsNumberMatchingDesc(nationalNumber, metadata.Pager)) return PhoneNumberType.PAGER; if (IsNumberMatchingDesc(nationalNumber, metadata.Uan)) return PhoneNumberType.UAN; if (IsNumberMatchingDesc(nationalNumber, metadata.Voicemail)) return PhoneNumberType.VOICEMAIL; var isFixedLine = IsNumberMatchingDesc(nationalNumber, metadata.FixedLine); if (isFixedLine) { if (metadata.SameMobileAndFixedLinePattern) return PhoneNumberType.FIXED_LINE_OR_MOBILE; else if (IsNumberMatchingDesc(nationalNumber, metadata.Mobile)) return PhoneNumberType.FIXED_LINE_OR_MOBILE; return PhoneNumberType.FIXED_LINE; } // Otherwise, test to see if the number is mobile. Only do this if certain that the patterns for // mobile and fixed line aren't the same. if (!metadata.SameMobileAndFixedLinePattern && IsNumberMatchingDesc(nationalNumber, metadata.Mobile)) return PhoneNumberType.MOBILE; return PhoneNumberType.UNKNOWN; }
/** * Appends the formatted extension of a phone number to formattedNumber, if the phone number had * an extension specified. */ private void MaybeAppendFormattedExtension(PhoneNumber number, PhoneMetadata metadata, PhoneNumberFormat numberFormat, StringBuilder formattedNumber) { if (number.HasExtension && number.Extension.Length > 0) { if (numberFormat == PhoneNumberFormat.RFC3966) { formattedNumber.Append(RFC3966_EXTN_PREFIX).Append(number.Extension); } else { if (metadata.HasPreferredExtnPrefix) formattedNumber.Append(metadata.PreferredExtnPrefix).Append(number.Extension); else formattedNumber.Append(DEFAULT_EXTN_PREFIX).Append(number.Extension); } } }
PhoneNumberDesc GetNumberDescByType(PhoneMetadata metadata, PhoneNumberType type) { switch (type) { case PhoneNumberType.PREMIUM_RATE: return metadata.PremiumRate; case PhoneNumberType.TOLL_FREE: return metadata.TollFree; case PhoneNumberType.MOBILE: return metadata.Mobile; case PhoneNumberType.FIXED_LINE: case PhoneNumberType.FIXED_LINE_OR_MOBILE: return metadata.FixedLine; case PhoneNumberType.SHARED_COST: return metadata.SharedCost; case PhoneNumberType.VOIP: return metadata.Voip; case PhoneNumberType.PERSONAL_NUMBER: return metadata.PersonalNumber; case PhoneNumberType.PAGER: return metadata.Pager; case PhoneNumberType.UAN: return metadata.Uan; case PhoneNumberType.VOICEMAIL: return metadata.Voicemail; default: return metadata.GeneralDesc; } }
// Note in some regions, the national number can be written in two completely different ways // depending on whether it forms part of the NATIONAL format or INTERNATIONAL format. The // numberFormat parameter here is used to specify which format to use for those cases. If a // carrierCode is specified, this will be inserted into the formatted string to replace $CC. private String FormatNsn(String number, PhoneMetadata metadata, PhoneNumberFormat numberFormat, String carrierCode) { var intlNumberFormats = metadata.IntlNumberFormatList; // When the intlNumberFormats exists, we use that to format national number for the // INTERNATIONAL format instead of using the numberDesc.numberFormats. var availableFormats = (intlNumberFormats.Count == 0 || numberFormat == PhoneNumberFormat.NATIONAL) ? metadata.NumberFormatList : metadata.IntlNumberFormatList; NumberFormat formattingPattern = ChooseFormattingPatternForNumber(availableFormats, number); return (formattingPattern == null) ? number : FormatNsnUsingPattern(number, formattingPattern, numberFormat, carrierCode); }
// Simple wrapper of formatNsn for the common case of no carrier code. private String FormatNsn(String number, PhoneMetadata metadata, PhoneNumberFormat numberFormat) { return FormatNsn(number, metadata, numberFormat, null); }
public Builder MergeFrom(PhoneMetadata other) { if (other == global::PhoneNumbers.PhoneMetadata.DefaultInstance) return this; if (other.HasGeneralDesc) { MergeGeneralDesc(other.GeneralDesc); } if (other.HasFixedLine) { MergeFixedLine(other.FixedLine); } if (other.HasMobile) { MergeMobile(other.Mobile); } if (other.HasTollFree) { MergeTollFree(other.TollFree); } if (other.HasPremiumRate) { MergePremiumRate(other.PremiumRate); } if (other.HasSharedCost) { MergeSharedCost(other.SharedCost); } if (other.HasPersonalNumber) { MergePersonalNumber(other.PersonalNumber); } if (other.HasVoip) { MergeVoip(other.Voip); } if (other.HasPager) { MergePager(other.Pager); } if (other.HasUan) { MergeUan(other.Uan); } if (other.HasEmergency) { MergeEmergency(other.Emergency); } if (other.HasVoicemail) { MergeVoicemail(other.Voicemail); } if (other.HasShortCode) { MergeShortCode(other.ShortCode); } if (other.HasStandardRate) { MergeStandardRate(other.StandardRate); } if (other.HasCarrierSpecific) { MergeCarrierSpecific(other.CarrierSpecific); } if (other.HasNoInternationalDialling) { MergeNoInternationalDialling(other.NoInternationalDialling); } if (other.HasId) { Id = other.Id; } if (other.HasCountryCode) { CountryCode = other.CountryCode; } if (other.HasInternationalPrefix) { InternationalPrefix = other.InternationalPrefix; } if (other.HasPreferredInternationalPrefix) { PreferredInternationalPrefix = other.PreferredInternationalPrefix; } if (other.HasNationalPrefix) { NationalPrefix = other.NationalPrefix; } if (other.HasPreferredExtnPrefix) { PreferredExtnPrefix = other.PreferredExtnPrefix; } if (other.HasNationalPrefixForParsing) { NationalPrefixForParsing = other.NationalPrefixForParsing; } if (other.HasNationalPrefixTransformRule) { NationalPrefixTransformRule = other.NationalPrefixTransformRule; } if (other.HasSameMobileAndFixedLinePattern) { SameMobileAndFixedLinePattern = other.SameMobileAndFixedLinePattern; } if (other.numberFormat_.Count != 0) { result.numberFormat_.AddRange(other.numberFormat_); } if (other.intlNumberFormat_.Count != 0) { result.intlNumberFormat_.AddRange(other.intlNumberFormat_); } if (other.HasMainCountryForCode) { MainCountryForCode = other.MainCountryForCode; } if (other.HasLeadingDigits) { LeadingDigits = other.LeadingDigits; } if (other.HasLeadingZeroPossible) { LeadingZeroPossible = other.LeadingZeroPossible; } if (other.HasMobileNumberPortableRegion) { MobileNumberPortableRegion = other.MobileNumberPortableRegion; } return this; }
/** * 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; }
public static Builder CreateBuilder(PhoneMetadata prototype) { return (Builder) new Builder().MergeFrom(prototype); }
/** * Tries to extract a country calling code from a number. This method will return zero if no * country calling code is considered to be present. Country calling codes are extracted in the * following ways: * <ul> * <li> by stripping the international dialing prefix of the region the person is dialing from, * if this is present in the number, and looking at the next digits * <li> by stripping the '+' sign if present and then looking at the next digits * <li> by comparing the start of the number and the country calling code of the default region. * If the number is not considered possible for the numbering plan of the default region * initially, but starts with the country calling code of this region, validation will be * reattempted after stripping this country calling code. If this number is considered a * possible number, then the first digits will be considered the country calling code and * removed as such. * </ul> * It will throw a NumberParseException if the number starts with a '+' but the country calling * code supplied after this does not match that of any known region. * * @param number non-normalized telephone number that we wish to extract a country calling * code from - may begin with '+' * @param defaultRegionMetadata metadata about the region this number may be from * @param nationalNumber a string buffer to store the national significant number in, in the case * that a country calling code was extracted. The number is appended to any existing contents. * If no country calling code was extracted, this will be left unchanged. * @param keepRawInput true if the country_code_source and preferred_carrier_code fields of * phoneNumber should be populated. * @param phoneNumber the PhoneNumber object where the country_code and country_code_source need * to be populated. Note the country_code is always populated, whereas country_code_source is * only populated when keepCountryCodeSource is true. * @return the country calling code extracted or 0 if none could be extracted */ public int MaybeExtractCountryCode(String number, PhoneMetadata defaultRegionMetadata, StringBuilder nationalNumber, bool keepRawInput, PhoneNumber.Builder phoneNumber) { if (number.Length == 0) return 0; StringBuilder fullNumber = new StringBuilder(number); // Set the default prefix to be something that will never match. String possibleCountryIddPrefix = "NonMatch"; if (defaultRegionMetadata != null) { possibleCountryIddPrefix = defaultRegionMetadata.InternationalPrefix; } CountryCodeSource countryCodeSource = MaybeStripInternationalPrefixAndNormalize(fullNumber, possibleCountryIddPrefix); if (keepRawInput) { phoneNumber.SetCountryCodeSource(countryCodeSource); } if (countryCodeSource != CountryCodeSource.FROM_DEFAULT_COUNTRY) { if (fullNumber.Length <= MIN_LENGTH_FOR_NSN) { throw new NumberParseException(ErrorType.TOO_SHORT_AFTER_IDD, "Phone number had an IDD, but after this was not " + "long enough to be a viable phone number."); } int potentialCountryCode = ExtractCountryCode(fullNumber, nationalNumber); if (potentialCountryCode != 0) { phoneNumber.SetCountryCode(potentialCountryCode); return potentialCountryCode; } // If this fails, they must be using a strange country calling code that we don't recognize, // or that doesn't exist. throw new NumberParseException(ErrorType.INVALID_COUNTRY_CODE, "Country calling code supplied was not recognised."); } else if (defaultRegionMetadata != null) { // Check to see if the number starts with the country calling code for the default region. If // so, we remove the country calling code, and do some checks on the validity of the number // before and after. int defaultCountryCode = defaultRegionMetadata.CountryCode; String defaultCountryCodeString = defaultCountryCode.ToString(); String normalizedNumber = fullNumber.ToString(); if (normalizedNumber.StartsWith(defaultCountryCodeString)) { StringBuilder potentialNationalNumber = new StringBuilder(normalizedNumber.Substring(defaultCountryCodeString.Length)); PhoneNumberDesc generalDesc = defaultRegionMetadata.GeneralDesc; var validNumberPattern = regexCache.GetPatternForRegex(generalDesc.NationalNumberPattern); MaybeStripNationalPrefixAndCarrierCode( potentialNationalNumber, defaultRegionMetadata, null /* Don't need the carrier code */); var possibleNumberPattern = regexCache.GetPatternForRegex(generalDesc.PossibleNumberPattern); // If the number was not valid before but is valid now, or if it was too long before, we // consider the number with the country calling code stripped to be a better result and // keep that instead. if ((!validNumberPattern.MatchAll(fullNumber.ToString()).Success && //XXX: ToString validNumberPattern.MatchAll(potentialNationalNumber.ToString()).Success) || //XXX: ToString TestNumberLengthAgainstPattern(possibleNumberPattern, fullNumber.ToString()) == ValidationResult.TOO_LONG) { nationalNumber.Append(potentialNationalNumber); if (keepRawInput) phoneNumber.SetCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN); phoneNumber.SetCountryCode(defaultCountryCode); return defaultCountryCode; } } } // No country calling code present. phoneNumber.SetCountryCode(0); return 0; }