diff --git a/cpp/src/phonenumbers/matcher_api.h b/cpp/src/phonenumbers/matcher_api.h index 91839fcd7..e46d02a65 100644 --- a/cpp/src/phonenumbers/matcher_api.h +++ b/cpp/src/phonenumbers/matcher_api.h @@ -36,9 +36,9 @@ class MatcherApi { // Returns whether the given national number (a string containing only decimal // digits) matches the national number pattern defined in the given // PhoneNumberDesc message. - virtual bool MatchesNationalNumber(const string& number, - const PhoneNumberDesc& number_desc, - bool allow_prefix_match) const = 0; + virtual bool MatchNationalNumber(const string& number, + const PhoneNumberDesc& number_desc, + bool allow_prefix_match) const = 0; }; } // namespace phonenumbers diff --git a/cpp/src/phonenumbers/phonenumberutil.cc b/cpp/src/phonenumbers/phonenumberutil.cc index 6b3299e87..960cf3ef8 100644 --- a/cpp/src/phonenumbers/phonenumberutil.cc +++ b/cpp/src/phonenumbers/phonenumberutil.cc @@ -34,11 +34,13 @@ #include "phonenumbers/base/memory/singleton.h" #include "phonenumbers/default_logger.h" #include "phonenumbers/encoding_utils.h" +#include "phonenumbers/matcher_api.h" #include "phonenumbers/metadata.h" #include "phonenumbers/normalize_utf8.h" #include "phonenumbers/phonemetadata.pb.h" #include "phonenumbers/phonenumber.h" #include "phonenumbers/phonenumber.pb.h" +#include "phonenumbers/regex_based_matcher.h" #include "phonenumbers/regexp_adapter.h" #include "phonenumbers/regexp_cache.h" #include "phonenumbers/regexp_factory.h" @@ -419,6 +421,13 @@ void CopyCoreFieldsOnly(const PhoneNumber& number, PhoneNumber* pruned_number) { } } +// Determines whether the given number is a national number match for the given +// PhoneNumberDesc. Does not check against possible lengths! +bool IsMatch(const MatcherApi& matcher_api, + const string& number, const PhoneNumberDesc& desc) { + return matcher_api.MatchNationalNumber(number, desc, false); +} + } // namespace void PhoneNumberUtil::SetLogger(Logger* logger) { @@ -736,6 +745,7 @@ class PhoneNumberRegExpsAndMappings { // Private constructor. Also takes care of initialisation. PhoneNumberUtil::PhoneNumberUtil() : logger_(Logger::set_logger_impl(new NullLogger())), + matcher_api_(new RegexBasedMatcher()), reg_exps_(new PhoneNumberRegExpsAndMappings), country_calling_code_to_region_code_map_(new vector()), nanpa_regions_(new set()), @@ -2412,9 +2422,7 @@ bool PhoneNumberUtil::IsNumberMatchingDesc( actual_length) == number_desc.possible_length().end()) { return false; } - return reg_exps_->regexp_cache_ - ->GetRegExp(number_desc.national_number_pattern()) - .FullMatch(national_number); + return IsMatch(*matcher_api_, national_number, number_desc); } PhoneNumberUtil::PhoneNumberType PhoneNumberUtil::GetNumberTypeHelper( @@ -2737,10 +2745,10 @@ bool PhoneNumberUtil::MaybeStripNationalPrefixAndCarrierCode( reg_exps_->regexp_factory_->CreateInput(*number)); string number_string_copy(*number); string captured_part_of_prefix; - const RegExp& national_number_rule = reg_exps_->regexp_cache_->GetRegExp( - metadata.general_desc().national_number_pattern()); + const PhoneNumberDesc& general_desc = metadata.general_desc(); // Check if the original number is viable. - bool is_viable_original_number = national_number_rule.FullMatch(*number); + bool is_viable_original_number = + IsMatch(*matcher_api_, *number, general_desc); // Attempt to parse the first digits as a national prefix. We make a // copy so that we can revert to the original string if necessary. const string& transform_rule = metadata.national_prefix_transform_rule(); @@ -2759,7 +2767,7 @@ bool PhoneNumberUtil::MaybeStripNationalPrefixAndCarrierCode( possible_national_prefix_pattern.Replace(&number_string_copy, transform_rule); if (is_viable_original_number && - !national_number_rule.FullMatch(number_string_copy)) { + !IsMatch(*matcher_api_, number_string_copy, general_desc)) { return false; } number->assign(number_string_copy); @@ -2777,7 +2785,7 @@ bool PhoneNumberUtil::MaybeStripNationalPrefixAndCarrierCode( const string number_copy_as_string = number_copy_without_transform->ToString(); if (is_viable_original_number && - !national_number_rule.FullMatch(number_copy_as_string)) { + !IsMatch(*matcher_api_, number_copy_as_string, general_desc)) { return false; } number->assign(number_copy_as_string); @@ -2924,9 +2932,6 @@ PhoneNumberUtil::ErrorType PhoneNumberUtil::MaybeExtractCountryCode( &potential_national_number)) { const PhoneNumberDesc& general_num_desc = default_region_metadata->general_desc(); - const RegExp& valid_number_pattern = - reg_exps_->regexp_cache_->GetRegExp( - general_num_desc.national_number_pattern()); MaybeStripNationalPrefixAndCarrierCode(*default_region_metadata, &potential_national_number, NULL); @@ -2935,8 +2940,9 @@ PhoneNumberUtil::ErrorType PhoneNumberUtil::MaybeExtractCountryCode( // 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 code stripped to // be a better result and keep that instead. - if ((!valid_number_pattern.FullMatch(*national_number) && - valid_number_pattern.FullMatch(potential_national_number)) || + if ((!IsMatch(*matcher_api_, *national_number, general_num_desc) && + IsMatch( + *matcher_api_, potential_national_number, general_num_desc)) || TestNumberLength(*national_number, *default_region_metadata) == TOO_LONG) { national_number->assign(potential_national_number); diff --git a/cpp/src/phonenumbers/phonenumberutil.h b/cpp/src/phonenumbers/phonenumberutil.h index 4750eb430..fc4f5dada 100644 --- a/cpp/src/phonenumbers/phonenumberutil.h +++ b/cpp/src/phonenumbers/phonenumberutil.h @@ -49,6 +49,7 @@ using google::protobuf::RepeatedPtrField; class AsYouTypeFormatter; class Logger; +class MatcherApi; class NumberFormat; class PhoneMetadata; class PhoneNumberDesc; @@ -774,6 +775,9 @@ class PhoneNumberUtil : public Singleton { // This corresponds to SECOND_NUMBER_START in the java version. static const char kCaptureUpToSecondNumberStart[]; + // An API for validation checking. + scoped_ptr matcher_api_; + // Helper class holding useful regular expressions and character mappings. scoped_ptr reg_exps_; diff --git a/cpp/src/phonenumbers/regex_based_matcher.cc b/cpp/src/phonenumbers/regex_based_matcher.cc index e9e1bcece..c1cc436c9 100644 --- a/cpp/src/phonenumbers/regex_based_matcher.cc +++ b/cpp/src/phonenumbers/regex_based_matcher.cc @@ -36,7 +36,7 @@ RegexBasedMatcher::RegexBasedMatcher() RegexBasedMatcher::~RegexBasedMatcher() {} -bool RegexBasedMatcher::MatchesNationalNumber( +bool RegexBasedMatcher::MatchNationalNumber( const string& national_number, const PhoneNumberDesc& number_desc, bool allow_prefix_match) const { return Match(national_number, number_desc.national_number_pattern(), diff --git a/cpp/src/phonenumbers/regex_based_matcher.h b/cpp/src/phonenumbers/regex_based_matcher.h index e1a594e16..ee3db7045 100644 --- a/cpp/src/phonenumbers/regex_based_matcher.h +++ b/cpp/src/phonenumbers/regex_based_matcher.h @@ -38,9 +38,9 @@ class RegexBasedMatcher : public MatcherApi { RegexBasedMatcher(); ~RegexBasedMatcher(); - bool MatchesNationalNumber(const string& national_number, - const PhoneNumberDesc& number_desc, - bool allow_prefix_match) const; + bool MatchNationalNumber(const string& national_number, + const PhoneNumberDesc& number_desc, + bool allow_prefix_match) const; private: bool Match(const string& national_number, const string& number_pattern, diff --git a/cpp/src/phonenumbers/shortnumberinfo.cc b/cpp/src/phonenumbers/shortnumberinfo.cc index ecc580cdf..0bef4b5c9 100644 --- a/cpp/src/phonenumbers/shortnumberinfo.cc +++ b/cpp/src/phonenumbers/shortnumberinfo.cc @@ -91,7 +91,7 @@ bool MatchesPossibleNumberAndNationalNumber( lengths.end()) { return false; } - return matcher_api.MatchesNationalNumber(number, desc, false); + return matcher_api.MatchNationalNumber(number, desc, false); } } // namespace @@ -363,7 +363,7 @@ bool ShortNumberInfo::MatchesEmergencyNumberHelper(const string& number, allow_prefix_match && regions_where_emergency_numbers_must_be_exact_->find(region_code) == regions_where_emergency_numbers_must_be_exact_->end(); - return matcher_api_->MatchesNationalNumber( + return matcher_api_->MatchNationalNumber( extracted_number, metadata->emergency(), allow_prefix_match_for_region); } diff --git a/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java b/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java index 2b2eab6e5..6c168c313 100644 --- a/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java +++ b/java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java @@ -21,6 +21,8 @@ import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata; import com.google.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc; import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource; +import com.google.i18n.phonenumbers.internal.MatcherApi; +import com.google.i18n.phonenumbers.internal.RegexBasedMatcher; import com.google.i18n.phonenumbers.internal.RegexCache; import java.util.ArrayList; @@ -577,6 +579,9 @@ public class PhoneNumberUtil { // first. private final Map> countryCallingCodeToRegionCodeMap; + // An API for validation checking. + private final MatcherApi matcherApi = RegexBasedMatcher.create(); + // The set of regions that share country calling code 1. // There are roughly 26 regions. // We set the initial capacity of the HashSet to 35 to offer a load factor of roughly 0.75. @@ -2233,10 +2238,7 @@ public class PhoneNumberUtil { if (possibleLengths.size() > 0 && !possibleLengths.contains(actualLength)) { return false; } - Matcher nationalNumberPatternMatcher = - regexCache.getPatternForRegex(numberDesc.getNationalNumberPattern()) - .matcher(nationalNumber); - return nationalNumberPatternMatcher.matches(); + return matcherApi.matchNationalNumber(nationalNumber, numberDesc, false); } /** @@ -2822,15 +2824,13 @@ public class PhoneNumberUtil { StringBuilder potentialNationalNumber = new StringBuilder(normalizedNumber.substring(defaultCountryCodeString.length())); PhoneNumberDesc generalDesc = defaultRegionMetadata.getGeneralDesc(); - Pattern validNumberPattern = - regexCache.getPatternForRegex(generalDesc.getNationalNumberPattern()); maybeStripNationalPrefixAndCarrierCode( potentialNationalNumber, defaultRegionMetadata, null /* Don't need the carrier code */); // 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.matcher(fullNumber).matches() - && validNumberPattern.matcher(potentialNationalNumber).matches()) + if ((!matcherApi.matchNationalNumber(fullNumber, generalDesc, false) + && matcherApi.matchNationalNumber(potentialNationalNumber, generalDesc, false)) || testNumberLength(fullNumber.toString(), defaultRegionMetadata) == ValidationResult.TOO_LONG) { nationalNumber.append(potentialNationalNumber); @@ -2926,10 +2926,9 @@ public class PhoneNumberUtil { // Attempt to parse the first digits as a national prefix. Matcher prefixMatcher = regexCache.getPatternForRegex(possibleNationalPrefix).matcher(number); if (prefixMatcher.lookingAt()) { - Pattern nationalNumberRule = - regexCache.getPatternForRegex(metadata.getGeneralDesc().getNationalNumberPattern()); + PhoneNumberDesc generalDesc = metadata.getGeneralDesc(); // Check if the original number is viable. - boolean isViableOriginalNumber = nationalNumberRule.matcher(number).matches(); + boolean isViableOriginalNumber = matcherApi.matchNationalNumber(number, generalDesc, false); // 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. @@ -2939,7 +2938,8 @@ public class PhoneNumberUtil { || prefixMatcher.group(numOfGroups) == null) { // If the original number was viable, and the resultant number is not, we return. if (isViableOriginalNumber - && !nationalNumberRule.matcher(number.substring(prefixMatcher.end())).matches()) { + && !matcherApi.matchNationalNumber( + number.substring(prefixMatcher.end()), generalDesc, false)) { return false; } if (carrierCode != null && numOfGroups > 0 && prefixMatcher.group(numOfGroups) != null) { @@ -2953,7 +2953,7 @@ public class PhoneNumberUtil { StringBuilder transformedNumber = new StringBuilder(number); transformedNumber.replace(0, numberLength, prefixMatcher.replaceFirst(transformRule)); if (isViableOriginalNumber - && !nationalNumberRule.matcher(transformedNumber.toString()).matches()) { + && !matcherApi.matchNationalNumber(transformedNumber.toString(), generalDesc, false)) { return false; } if (carrierCode != null && numOfGroups > 1) { diff --git a/java/libphonenumber/src/com/google/i18n/phonenumbers/ShortNumberInfo.java b/java/libphonenumber/src/com/google/i18n/phonenumbers/ShortNumberInfo.java index 411b19e99..e77ffd4d8 100644 --- a/java/libphonenumber/src/com/google/i18n/phonenumbers/ShortNumberInfo.java +++ b/java/libphonenumber/src/com/google/i18n/phonenumbers/ShortNumberInfo.java @@ -450,7 +450,7 @@ public class ShortNumberInfo { PhoneNumberDesc emergencyDesc = metadata.getEmergency(); boolean allowPrefixMatchForRegion = allowPrefixMatch && !REGIONS_WHERE_EMERGENCY_NUMBERS_MUST_BE_EXACT.contains(regionCode); - return matcherApi.matchesNationalNumber(normalizedNumber, emergencyDesc, + return matcherApi.matchNationalNumber(normalizedNumber, emergencyDesc, allowPrefixMatchForRegion); } @@ -531,6 +531,6 @@ public class ShortNumberInfo { && !numberDesc.getPossibleLengthList().contains(number.length())) { return false; } - return matcherApi.matchesNationalNumber(number, numberDesc, false); + return matcherApi.matchNationalNumber(number, numberDesc, false); } } diff --git a/java/libphonenumber/src/com/google/i18n/phonenumbers/internal/MatcherApi.java b/java/libphonenumber/src/com/google/i18n/phonenumbers/internal/MatcherApi.java index db5400e77..d2c32b9ea 100644 --- a/java/libphonenumber/src/com/google/i18n/phonenumbers/internal/MatcherApi.java +++ b/java/libphonenumber/src/com/google/i18n/phonenumbers/internal/MatcherApi.java @@ -27,6 +27,6 @@ public interface MatcherApi { * Returns whether the given national number (a string containing only decimal digits) matches * the national number pattern defined in the given {@code PhoneNumberDesc} message. */ - boolean matchesNationalNumber(String number, PhoneNumberDesc numberDesc, + boolean matchNationalNumber(CharSequence number, PhoneNumberDesc numberDesc, boolean allowPrefixMatch); } diff --git a/java/libphonenumber/src/com/google/i18n/phonenumbers/internal/RegexBasedMatcher.java b/java/libphonenumber/src/com/google/i18n/phonenumbers/internal/RegexBasedMatcher.java index 7bd121cbd..96b0b8487 100644 --- a/java/libphonenumber/src/com/google/i18n/phonenumbers/internal/RegexBasedMatcher.java +++ b/java/libphonenumber/src/com/google/i18n/phonenumbers/internal/RegexBasedMatcher.java @@ -34,7 +34,7 @@ public final class RegexBasedMatcher implements MatcherApi { private RegexBasedMatcher() {} // @Override - public boolean matchesNationalNumber(String nationalNumber, PhoneNumberDesc numberDesc, + public boolean matchNationalNumber(CharSequence nationalNumber, PhoneNumberDesc numberDesc, boolean allowPrefixMatch) { Matcher nationalNumberPatternMatcher = regexCache.getPatternForRegex( numberDesc.getNationalNumberPattern()).matcher(nationalNumber);