2121
2222# Extra regexp function; see README
2323from re_util import fullmatch
24+ import unicode_util
2425import phonenumberutil
2526
2627
@@ -64,7 +65,7 @@ def _limit(lower, upper):
6465_DIGIT_BLOCK_LIMIT = (phonenumberutil ._MAX_LENGTH_FOR_NSN +
6566 phonenumberutil ._MAX_LENGTH_COUNTRY_CODE )
6667# Limit on the number of blocks separated by punctuation. Use _DIGIT_BLOCK_LIMIT
67- # since in some formats use spaces to separate each digit.
68+ # since some formats use spaces to separate each digit.
6869_BLOCK_LIMIT = _limit (0 , _DIGIT_BLOCK_LIMIT )
6970
7071# A punctuation sequence allowing white space.
@@ -73,6 +74,7 @@ def _limit(lower, upper):
7374_DIGIT_SEQUENCE = u"(?u)\\ d" + _limit (1 , _DIGIT_BLOCK_LIMIT )
7475# Punctuation that may be at the start of a phone number - brackets and plus signs.
7576_LEAD_CLASS = u"[" + _OPENING_PARENS + phonenumberutil ._PLUS_CHARS + u"]"
77+ _LEAD_PATTERN = re .compile (_LEAD_CLASS )
7678
7779# Phone number pattern allowing optional punctuation.
7880# This is the phone number pattern used by _find(), similar to
@@ -244,6 +246,23 @@ def _trim_after_first_match(self, pattern, candidate):
244246 candidate = candidate [:trailing_chars_match .start ()]
245247 return candidate
246248
249+ @classmethod
250+ def _is_latin_letter (self , letter ):
251+ """Helper method to determine if a character is a Latin-script letter
252+ or not. For our purposes, combining marks should also return true
253+ since we assume they have been added to a preceding Latin character."""
254+ # Combining marks are a subset of non-spacing-mark
255+ if (not unicode_util .is_letter (letter ) and
256+ unicode_util .Category .get (letter ) != unicode_util .Category .NON_SPACING_MARK ):
257+ return False
258+ block = unicode_util .Block .get (letter )
259+ return (block == unicode_util .Block .BASIC_LATIN or
260+ block == unicode_util .Block .LATIN_1_SUPPLEMENT or
261+ block == unicode_util .Block .LATIN_EXTENDED_A or
262+ block == unicode_util .Block .LATIN_EXTENDED_ADDITIONAL or
263+ block == unicode_util .Block .LATIN_EXTENDED_B or
264+ block == unicode_util .Block .COMBINING_DIACRITICAL_MARKS )
265+
247266 def _extract_match (self , candidate , offset ):
248267 """Attempts to extract a match from a candidate string.
249268
@@ -258,6 +277,22 @@ def _extract_match(self, candidate, offset):
258277 _SLASH_SEPARATED_DATES .search (candidate )):
259278 return None
260279
280+ # If leniency is set to VALID only, we also want to skip numbers that
281+ # are surrounded by Latin alphabetic characters, to skip cases like
282+ # abc8005001234 or 8005001234def.
283+ if self .leniency == Leniency .VALID :
284+ # If the candidate is not at the start of the text, and does not
285+ # start with punctuation and the previous character is not a Latin
286+ # letter, return None.
287+ if (offset > 0 and
288+ not _LEAD_PATTERN .match (candidate ) and
289+ self ._is_latin_letter (self .text [offset - 1 ])):
290+ return None
291+ last_char_index = offset + len (candidate )
292+ if (last_char_index < len (self .text ) and
293+ self ._is_latin_letter (self .text [last_char_index ])):
294+ return None
295+
261296 # Try to come up with a valid match given the entire candidate.
262297 match = self ._parse_and_verify (candidate , offset )
263298 if match is not None :
@@ -278,7 +313,7 @@ def _extract_inner_match(self, candidate, offset):
278313 """
279314 # Try removing either the first or last "group" in the number and see
280315 # if this gives a result. We consider white space to be a possible
281- # indications of the start or end of the phone number.
316+ # indication of the start or end of the phone number.
282317 group_match = _GROUP_SEPARATOR .search (candidate )
283318 if group_match :
284319 group_start_index = group_match .end ()
0 commit comments