@@ -3203,49 +3203,93 @@ private void parseHelper(CharSequence numberToParse, String defaultRegion,
32033203 }
32043204
32053205 /**
3206- * Converts numberToParse to a form that we can parse and write it to nationalNumber if it is
3207- * written in RFC3966; otherwise extract a possible number out of it and write to nationalNumber .
3206+ * Converts numberToParse to a form that we can parse and write it to outputNumber if it is
3207+ * written in RFC3966; otherwise extract a possible number out of it and write to outputNumber .
32083208 */
3209- private void buildNationalNumberForParsing (String numberToParse , StringBuilder nationalNumber )
3209+ // @VisibleForTesting
3210+ void buildNationalNumberForParsing (String numberToParse , StringBuilder outputNumber )
32103211 throws NumberParseException {
3211- int indexOfPhoneContext = numberToParse .indexOf (Constants .RFC3966_PHONE_CONTEXT );
3212-
32133212 PhoneContext phoneContext = phoneContextParser .parse (numberToParse );
32143213
3215- if (phoneContext != null ) {
3216- // If the phone context contains a phone number prefix, we need to capture it, whereas domains
3217- // will be ignored.
3218- if (phoneContext .getRawContext ().charAt (0 ) == Constants .PLUS_SIGN ) {
3219- // Additional parameters might follow the phone context. If so, we will remove them here
3220- // because the parameters after phone context are not important for parsing the phone
3221- // number.
3222- nationalNumber .append (phoneContext .getRawContext ());
3223- }
3224-
3225- // Now append everything between the "tel:" prefix and the phone-context. This should include
3226- // the national number, an optional extension or isdn-subaddress component. Note we also
3227- // handle the case when "tel:" is missing, as we have seen in some of the phone number inputs.
3228- // In that case, we append everything from the beginning.
3229- int indexOfRfc3966Prefix = numberToParse .indexOf (RFC3966_PREFIX );
3230- int indexOfNationalNumber =
3231- (indexOfRfc3966Prefix >= 0 ) ? indexOfRfc3966Prefix + RFC3966_PREFIX .length () : 0 ;
3232- nationalNumber .append (numberToParse .substring (indexOfNationalNumber , indexOfPhoneContext ));
3233- } else {
3214+ if (phoneContext == null ) {
32343215 // Extract a possible number from the string passed in (this strips leading characters that
32353216 // could not be the start of a phone number.)
3236- nationalNumber .append (extractPossibleNumber (numberToParse ));
3217+ outputNumber .append (extractPossibleNumber (numberToParse ));
3218+
3219+ // Strip the isdn parameter if present
3220+ int idsnPrefixStart = outputNumber .indexOf (RFC3966_ISDN_SUBADDRESS );
3221+ if (idsnPrefixStart > 0 ) {
3222+ outputNumber .delete (idsnPrefixStart , outputNumber .length ());
3223+ }
3224+ return ;
32373225 }
32383226
3239- // Delete the isdn-subaddress and everything after it if it is present. Note extension won't
3240- // appear at the same time with isdn-subaddress according to paragraph 5.3 of the RFC3966 spec,
3241- int indexOfIsdn = nationalNumber .indexOf (RFC3966_ISDN_SUBADDRESS );
3242- if (indexOfIsdn > 0 ) {
3243- nationalNumber .delete (indexOfIsdn , nationalNumber .length ());
3227+ // Note we also handle the case when "tel:" is missing. In that case, we consider the start of
3228+ // the string to be the start of the number.
3229+ int rfc3966PrefixStart = numberToParse .indexOf (RFC3966_PREFIX );
3230+ int numberStart =
3231+ (rfc3966PrefixStart >= 0 ) ? rfc3966PrefixStart + RFC3966_PREFIX .length () : 0 ;
3232+ int numberEnd = numberToParse .indexOf (";" , numberStart );
3233+
3234+ if (numberEnd < 0 ) {
3235+ // If there is no semicolon, we assume the rest of the string is the national number.
3236+ // This should not happen, since we expect to find a semicolon if there is a phone-context.
3237+ numberEnd = numberToParse .length ();
32443238 }
3245- // If both phone context and isdn-subaddress are absent but other parameters are present, the
3246- // parameters are left in nationalNumber. This is because we are concerned about deleting
3247- // content from a potential number string when there is no strong evidence that the number is
3248- // actually written in RFC3966.
3239+
3240+ String numberPart = numberToParse .substring (numberStart , numberEnd );
3241+
3242+ outputNumber .append (constructE164 (phoneContext , numberPart ));
3243+
3244+ // Append the extension if present.
3245+ int extnPrefixStart = numberToParse .indexOf (RFC3966_EXTN_PREFIX );
3246+ if (extnPrefixStart >= 0 ) {
3247+ int extnStart = extnPrefixStart + RFC3966_EXTN_PREFIX .length ();
3248+ int extnEnd = numberToParse .indexOf (";" , extnStart );
3249+ if (extnEnd < 0 ) {
3250+ extnEnd = numberToParse .length ();
3251+ }
3252+ outputNumber .append (DEFAULT_EXTN_PREFIX ).append (numberToParse , extnStart , extnEnd );
3253+ }
3254+ }
3255+
3256+ /**
3257+ * Attempts to construct an E164 number from the parsed phone context and numberPart and returns
3258+ * it.
3259+ *
3260+ * If the phone context is a country code, the national prefix is stripped from the numberPart and
3261+ * the E164 number is constructed from the country code and the stripped number.
3262+ *
3263+ * If the phone context is more than just a country code, we fall back to concatenating the whole
3264+ * context with the numberPart.
3265+ */
3266+ private String constructE164 (PhoneContext phoneContext , String numberPart ) {
3267+ if (phoneContext .getRawContext ().charAt (0 ) != Constants .PLUS_SIGN ) {
3268+ return numberPart ;
3269+ }
3270+
3271+ if (phoneContext .getCountryCode () == null ) {
3272+ // Fall back to prefixing the national number with the country calling code if the context
3273+ // is more than just a country calling code.
3274+ return phoneContext .getRawContext () + numberPart ;
3275+ }
3276+
3277+ // Get the region code and metadata from the phone context country code.
3278+ String regionCode = getRegionCodeForCountryCode (phoneContext .getCountryCode ());
3279+ PhoneMetadata regionMetadata = getMetadataForRegionOrCallingCode (phoneContext .getCountryCode (), regionCode );
3280+
3281+ if (regionMetadata == null ) {
3282+ // Fall back to prefixing the national number with the country calling code if the country
3283+ // code is invalid.
3284+ return phoneContext .getRawContext () + numberPart ;
3285+ }
3286+
3287+ StringBuilder numberWithoutNationalPrefix = new StringBuilder (numberPart );
3288+ maybeStripNationalPrefixAndCarrierCode (numberWithoutNationalPrefix , regionMetadata ,
3289+ new StringBuilder ());
3290+
3291+ return Constants .PLUS_SIGN + phoneContext .getCountryCode ().toString ()
3292+ + numberWithoutNationalPrefix ;
32493293 }
32503294
32513295 /**
0 commit comments