diff --git a/src/phonenumberutil/phonenumberutil.rs b/src/phonenumberutil/phonenumberutil.rs index 6d0ed7c..70a88fd 100644 --- a/src/phonenumberutil/phonenumberutil.rs +++ b/src/phonenumberutil/phonenumberutil.rs @@ -1268,127 +1268,131 @@ impl PhoneNumberUtil { } } - fn FormatOutOfCountryKeepingAlphaChars<'a>( + fn format_out_of_country_keeping_alpha_chars<'a>( &self, phone_number: &'a PhoneNumber, calling_from: &str, - ) -> Cow<'a, str> { + ) -> RegexResult> { // 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 (number.raw_input().empty()){ - return self.format_out_of_country_calling_number(phone_number, calling_from); - FormatOutOfCountryCallingNumber(number, calling_from, formatted_number); - return; + if phone_number.raw_input().is_empty() { + return self.format_out_of_country_calling_number(phone_number, calling_from) } - int country_code = number.country_code(); - if (!HasValidCountryCallingCode(country_code)) - { - formatted_number->assign(number.raw_input()); - return; + + let country_code = phone_number.country_code(); + if !self.has_valid_country_calling_code(country_code) { + return Ok(phone_number.raw_input().into()) } // 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. - string raw_input_copy(number.raw_input()); // Normalize punctuation. We retain number grouping symbols such as " " only. - NormalizeHelper(reg_exps_->all_plus_number_grouping_symbols_, true, - &raw_input_copy); + let mut normalized_raw_input = helper_functions::normalize_helper( + &self.reg_exps.all_plus_number_grouping_symbols, + true, + phone_number.raw_input() + ); // 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. - string national_number; - GetNationalSignificantNumber(number, &national_number); - if (national_number.length() > 3) - { - size_t first_national_number_digit = - raw_input_copy.find(national_number.substr(0, 3)); - if (first_national_number_digit != string::npos) - { - raw_input_copy = raw_input_copy.substr(first_national_number_digit); + let national_number = Self::get_national_significant_number(phone_number); + if national_number.len() > 3 { + let first_national_number_digit = normalized_raw_input + .find(&national_number[0..3]); + if let Some(first_national_number_digit) = first_national_number_digit { + normalized_raw_input.drain(0..first_national_number_digit); } } - const PhoneMetadata *metadata = GetMetadataForRegion(calling_from); - if (country_code == kNanpaCountryCode) - { - if (IsNANPACountry(calling_from)) - { - StrAppend(formatted_number, country_code, " ", raw_input_copy); - return; + let metadata = self.region_to_metadata_map.get(calling_from); + if country_code == NANPA_COUNTRY_CODE { + if self.nanpa_regions.contains(calling_from) { + let mut buf = itoa::Buffer::new(); + + return Ok(fast_cat::concat_str!( + buf.format(country_code), " ", &normalized_raw_input + ).into()); } } - else if (metadata && - country_code == GetCountryCodeForValidRegion(calling_from)) - { - const NumberFormat *formatting_pattern = - ChooseFormattingPatternForNumber(metadata->number_format(), - national_number); - if (!formatting_pattern) - { + else if let Some(metadata) = metadata.filter( + |metadata| country_code == metadata.country_code() + ) { + let Some(formatting_pattern) = self.choose_formatting_pattern_for_number( + &metadata.number_format, &national_number + )? else { // If no pattern above is matched, we format the original input. - formatted_number->assign(raw_input_copy); - return; - } - NumberFormat new_format; - new_format.MergeFrom(*formatting_pattern); + return Ok(normalized_raw_input.into()) + }; + let mut new_format = formatting_pattern.clone(); // The first group is the first group of digits that the user wrote // together. - new_format.set_pattern("(\\d+)(.*)"); + new_format.set_pattern("(\\d+)(.*)".to_owned()); // Here we just concatenate them back together after the national prefix // has been fixed. - new_format.set_format("$1$2"); + new_format.set_format("$1$2".to_owned()); // 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. - FormatNsnUsingPattern(raw_input_copy, new_format, NATIONAL, - formatted_number); - return; + return self.format_nsn_using_pattern( + &normalized_raw_input, + &new_format, + PhoneNumberFormat::National + ).map(| cow | Cow::Owned(cow.into_owned()) ); } - string international_prefix_for_formatting; // 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 (metadata) - { - const string &international_prefix = metadata->international_prefix(); - international_prefix_for_formatting = - reg_exps_->single_international_prefix_->FullMatch(international_prefix) - ? international_prefix - : metadata->preferred_international_prefix(); - } - if (!international_prefix_for_formatting.empty()) - { - StrAppend(formatted_number, international_prefix_for_formatting, " ", - country_code, " ", raw_input_copy); - } - else - { + let international_prefix_for_formatting = metadata.map(| metadata | { + let international_prefix = metadata.international_prefix(); + if self.reg_exps.single_international_prefix + .full_match(international_prefix) { + international_prefix + } else { + metadata.preferred_international_prefix() + } + }); + let formatted_number = if let Some(international_prefix_for_formatting) = international_prefix_for_formatting { + let mut buf = itoa::Buffer::new(); + fast_cat::concat_str!( + international_prefix_for_formatting, " ", + buf.format(country_code), " ", &normalized_raw_input + ) + } else { // Invalid region entered as country-calling-from (so no metadata was found // for it) or the region chosen has multiple international dialling // prefixes. - if (!IsValidRegionCode(calling_from)) - { - VLOG(1) << "Trying to format number from invalid region " << calling_from - << ". International formatting applied."; + if !self.region_to_metadata_map.contains_key(calling_from) { + trace!( + "Trying to format number from invalid region {}. International formatting applied.", + calling_from + ); } - formatted_number->assign(raw_input_copy); - PrefixNumberWithCountryCallingCode(country_code, INTERNATIONAL, - formatted_number); - } - std::string region_code; - GetRegionCodeForCountryCode(country_code, ®ion_code); + let mut formatted_number = normalized_raw_input; + prefix_number_with_country_calling_code(country_code, PhoneNumberFormat::International, &mut formatted_number); + formatted_number + }; + let region_code = self.get_region_code_for_country_code(country_code); // Metadata cannot be null because the country code is valid. - const PhoneMetadata *metadata_for_region = - GetMetadataForRegionOrCallingCode(country_code, region_code); + let metadata_for_region = self + .get_metadata_for_region_or_calling_code(country_code, region_code) + .expect("Metadata cannot be null because the country code is valid."); + // Strip any extension - std::string extension; - MaybeStripExtension(formatted_number, &extension); + let (phone_number_without_extension, extension) = self + .maybe_strip_extension(&formatted_number); // Append the formatted extension - MaybeAppendFormattedExtension(number, *metadata_for_region, INTERNATIONAL, - formatted_number); + let extension = Self::get_formatted_extension(phone_number, metadata_for_region, PhoneNumberFormat::International); + Ok( + if let Some(extension) = extension { + fast_cat::concat_str!(phone_number_without_extension, &extension) + } else { + phone_number_without_extension.to_string() + } + .into() + ) }