/// <summary> /// Parses a phone number from the {@code candidate} using {@link PhoneNumberUtil#parse} and /// verifies it matches the requested {@link #leniency}. If parsing and verification succeed, a /// corresponding <see cref="PhoneNumberMatch" /> is returned, otherwise this method returns null. /// </summary> /// /// <param name="candidate">the candidate match</param> /// <param name="offset">the offset of <c>candidate</c> within <see cref="text" /></param> /// <returns>the parsed and validated phone number match, or null</returns> private PhoneNumberMatch ParseAndVerify(string candidate, int offset) { try { // Check the candidate doesn't contain any formatting which would indicate that it really // isn't a phone number. if (!MatchingBrackets.IsMatchAll(candidate)) { return(null); } // If leniency is set to VALID or stricter, we also want to skip numbers that are surrounded // by Latin alphabetic characters, to skip cases like abc8005001234 or 8005001234def. if (leniency >= PhoneNumberUtil.Leniency.VALID) { // If the candidate is not at the start of the text, and does not start with phone-number // punctuation, check the previous character. if (offset > 0 && !LeadClass.IsMatchBeginning(candidate)) { var previousChar = text[offset - 1]; // We return null if it is a latin letter or an invalid punctuation symbol. if (IsInvalidPunctuationSymbol(previousChar) || IsLatinLetter(previousChar)) { return(null); } } var lastCharIndex = offset + candidate.Length; if (lastCharIndex < text.Length) { var nextChar = text[lastCharIndex]; if (IsInvalidPunctuationSymbol(nextChar) || IsLatinLetter(nextChar)) { return(null); } } } var number = phoneUtil.ParseAndKeepRawInput(candidate, preferredRegion); if (leniency.Verify(number, candidate, phoneUtil, this)) { // We used parseAndKeepRawInput to create this number, but for now we don't return the extra // values parsed. TODO: stop clearing all values here and switch all users over // to using rawInput() rather than the rawString() of PhoneNumberMatch. var bnumber = number.ToBuilder(); bnumber.ClearCountryCodeSource(); bnumber.ClearRawInput(); bnumber.ClearPreferredDomesticCarrierCode(); return(new PhoneNumberMatch(offset, candidate, bnumber.Build())); } } catch (NumberParseException) { // ignore and continue } return(null); }
private void GetAvailableFormats(string leadingDigits) { // First decide whether we should use international or national number rules. var isInternationalNumber = isCompleteNumber && extractedNationalPrefix.Length == 0; var formatList = isInternationalNumber && currentMetadata.IntlNumberFormatCount > 0 ? currentMetadata.IntlNumberFormatList : currentMetadata.NumberFormatList; foreach (var format in formatList) { // Discard a few formats that we know are not relevant based on the presence of the national // prefix. if (extractedNationalPrefix.Length > 0 && PhoneNumberUtil.FormattingRuleHasFirstGroupOnly( format.NationalPrefixFormattingRule) && !format.NationalPrefixOptionalWhenFormatting && !format.HasDomesticCarrierCodeFormattingRule) { // If it is a national number that had a national prefix, any rules that aren't valid with a // national prefix should be excluded. A rule that has a carrier-code formatting rule is // kept since the national prefix might actually be an extracted carrier code - we don't // distinguish between these when extracting it in the AYTF. continue; } else if (extractedNationalPrefix.Length == 0 && !isCompleteNumber && !PhoneNumberUtil.FormattingRuleHasFirstGroupOnly( format.NationalPrefixFormattingRule) && !format.NationalPrefixOptionalWhenFormatting) { // This number was entered without a national prefix, and this formatting rule requires one, // so we discard it. continue; } if (EligibleFormatPattern.IsMatchAll(format.Format)) { possibleFormats.Add(format); } } NarrowDownPossibleFormats(leadingDigits); }