Skip to content

Commit 45bb6bc

Browse files
committed
Merge code changes from upstream r594
1 parent fc21b9e commit 45bb6bc

4 files changed

Lines changed: 94 additions & 13 deletions

File tree

python/phonenumbers/phonenumbermatcher.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ class Leniency(object):
163163
# written as "65 02 53 00 00" and "650253 0000" are not accepted at this
164164
# leniency level, whereas "650 253 0000", "650 2530000" or "6502530000"
165165
# are.
166-
# Numbers with more than one '/' symbol are also dropped at this level.
166+
# Numbers with more than one '/' symbol in the national significant number
167+
# are also dropped at this level.
168+
#
167169
# Warning: This level might result in lower coverage especially for
168170
# regions outside of country code "+1". If you are not sure about which
169171
# level to use, email the discussion group
@@ -202,7 +204,7 @@ def _verify(leniency, numobj, candidate):
202204
def _verify_strict_grouping(numobj, candidate):
203205
if (not is_valid_number(numobj) or
204206
not _contains_only_valid_x_chars(numobj, candidate) or
205-
_contains_more_than_one_slash(candidate) or
207+
_contains_more_than_one_slash_in_national_number(numobj, candidate) or
206208
not _is_national_prefix_present_if_required(numobj)):
207209
return False
208210
return _check_number_grouping_is_valid(numobj, candidate,
@@ -251,7 +253,7 @@ def _all_number_groups_remain_grouped(numobj, normalized_candidate, formatted_nu
251253
def _verify_exact_grouping(numobj, candidate):
252254
if (not is_valid_number(numobj) or
253255
not _contains_only_valid_x_chars(numobj, candidate) or
254-
_contains_more_than_one_slash(candidate) or
256+
_contains_more_than_one_slash_in_national_number(numobj, candidate) or
255257
not _is_national_prefix_present_if_required(numobj)):
256258
return False
257259
return _check_number_grouping_is_valid(numobj, candidate,
@@ -337,10 +339,26 @@ def _check_number_grouping_is_valid(numobj, candidate, checker):
337339
return False
338340

339341

340-
def _contains_more_than_one_slash(candidate):
341-
first_slash_index = candidate.find(u'/')
342-
return (first_slash_index > 0 and
343-
(candidate.find(u'/', (first_slash_index + 1)) != -1))
342+
def _contains_more_than_one_slash_in_national_number(numobj, candidate):
343+
first_slash_in_body_index = candidate.find(u'/')
344+
if first_slash_in_body_index < 0:
345+
# No slashes, this is okay.
346+
return False
347+
# Now look for a second one.
348+
second_slash_in_body_index = candidate.find(u'/', first_slash_in_body_index + 1)
349+
if second_slash_in_body_index < 0:
350+
# Only one slash, this is okay.,
351+
return False
352+
353+
# If the first slash is after the country calling code, this is permitted.
354+
candidate_has_country_code = (numobj.country_code_source == CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN or
355+
numobj.country_code_source == CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN)
356+
if (candidate_has_country_code and
357+
normalize_digits_only(candidate[:first_slash_in_body_index]) ==
358+
unicode(numobj.country_code)):
359+
# Any more slashes and this is illegal.
360+
return (candidate[(second_slash_in_body_index + 1):].find(u'/') != -1)
361+
return True
344362

345363

346364
def _contains_only_valid_x_chars(numobj, candidate):

python/phonenumbers/phonenumberutil.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,19 @@ def normalize_digits_only(number, keep_non_digits=False):
528528
return normalized_digits
529529

530530

531+
def _normalize_diallable_chars_only(number):
532+
"""Normalizes a string of characters representing a phone number.
533+
534+
This strips all characters which are not diallable on a mobile phone
535+
keypad (including all non-ASCII digits).
536+
537+
Arguments:
538+
number -- a string of characters representing a phone number
539+
540+
Returns the normalized string version of the phone number.
541+
"""
542+
return _normalize_helper(number, _DIALLABLE_CHAR_MAPPINGS, True)
543+
531544
def convert_alpha_characters_in_number(number):
532545
"""Convert alpha chars in a number to their respective digits on a keypad,
533546
but retains existing formatting."""
@@ -988,8 +1001,7 @@ def format_number_for_mobile_dialing(numobj, region_calling_from, with_formattin
9881001
if with_formatting:
9891002
return formatted_number
9901003
else:
991-
return _normalize_helper(formatted_number, _DIALLABLE_CHAR_MAPPINGS,
992-
True) # remove non matches
1004+
return _normalize_diallable_chars_only(formatted_number)
9931005

9941006

9951007
def format_out_of_country_calling_number(numobj, region_calling_from):
@@ -1111,8 +1123,8 @@ def format_in_original_format(numobj, region_calling_from):
11111123
# the user entered.
11121124
if (formatted_number is not None and
11131125
num_raw_input is not None and len(num_raw_input) > 0):
1114-
normalized_formatted_number = _normalize_helper(formatted_number, _DIALLABLE_CHAR_MAPPINGS, True)
1115-
normalized_raw_input = _normalize_helper(num_raw_input, _DIALLABLE_CHAR_MAPPINGS, True)
1126+
normalized_formatted_number = _normalize_diallable_chars_only(formatted_number)
1127+
normalized_raw_input = _normalize_diallable_chars_only(num_raw_input)
11161128
if normalized_formatted_number != normalized_raw_input:
11171129
formatted_number = num_raw_input
11181130
return formatted_number
@@ -1607,13 +1619,19 @@ def _number_type_helper(national_number, metadata):
16071619
return PhoneNumberType.UNKNOWN
16081620

16091621

1622+
def _is_number_possible_for_desc(national_number, number_desc):
1623+
if number_desc is None:
1624+
return False
1625+
possible_re = re.compile(number_desc.possible_number_pattern or "")
1626+
return fullmatch(possible_re, national_number)
1627+
1628+
16101629
def _is_number_matching_desc(national_number, number_desc):
16111630
"""Determine if the number matches the given PhoneNumberDesc"""
16121631
if number_desc is None:
16131632
return False
1614-
possible_re = re.compile(number_desc.possible_number_pattern or "")
16151633
national_re = re.compile(number_desc.national_number_pattern or "")
1616-
return (fullmatch(possible_re, national_number) and
1634+
return (_is_number_possible_for_desc(national_number, number_desc) and
16171635
fullmatch(national_re, national_number))
16181636

16191637

python/tests/phonenumbermatchertest.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from phonenumbers import PhoneNumberMatch, PhoneNumberMatcher, Leniency
2424
from phonenumbers import PhoneNumber, NumberFormat, phonenumberutil
25+
from phonenumbers import phonenumbermatcher, CountryCodeSource
2526
from .testmetadatatest import TestMetadataTestCase
2627

2728

@@ -219,6 +220,43 @@ class PhoneNumberMatcherTest(TestMetadataTestCase):
219220
This only tests basic functionality based on test metadata. See
220221
testphonenumberutil.py for the origin of the test data.
221222
"""
223+
def testContainsMoreThanOneSlashInNationalNumber(self):
224+
# A date should return true.
225+
number = PhoneNumber(country_code=1,
226+
country_code_source=CountryCodeSource.FROM_DEFAULT_COUNTRY)
227+
candidate = "1/05/2013"
228+
self.assertTrue(phonenumbermatcher._contains_more_than_one_slash_in_national_number(number, candidate))
229+
230+
# Here, the country code source thinks it started with a country calling code, but this is not
231+
# the same as the part before the slash, so it's still true.
232+
number = PhoneNumber(country_code=274,
233+
country_code_source=CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN)
234+
candidate = "27/4/2013"
235+
self.assertTrue(phonenumbermatcher._contains_more_than_one_slash_in_national_number(number, candidate))
236+
237+
# Now it should be false, because the first slash is after the country calling code.
238+
number = PhoneNumber(country_code=49,
239+
country_code_source=CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)
240+
candidate = "49/69/2013"
241+
self.assertFalse(phonenumbermatcher._contains_more_than_one_slash_in_national_number(number, candidate))
242+
243+
number = PhoneNumber(country_code=49,
244+
country_code_source=CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN)
245+
candidate = "+49/69/2013"
246+
self.assertFalse(phonenumbermatcher._contains_more_than_one_slash_in_national_number(number, candidate))
247+
248+
candidate = "+ 49/69/2013"
249+
self.assertFalse(phonenumbermatcher._contains_more_than_one_slash_in_national_number(number, candidate))
250+
251+
candidate = "+ 49/69/20/13"
252+
self.assertTrue(phonenumbermatcher._contains_more_than_one_slash_in_national_number(number, candidate))
253+
254+
# Here, the first group is not assumed to be the country calling code, even though it is the
255+
# same as it, so this should return true.
256+
number = PhoneNumber(country_code=49,
257+
country_code_source=CountryCodeSource.FROM_DEFAULT_COUNTRY)
258+
candidate = "49/69/2013"
259+
self.assertTrue(phonenumbermatcher._contains_more_than_one_slash_in_national_number(number, candidate))
222260

223261
# See PhoneNumberUtilTest.testParseNationalNumber().
224262
def testFindNationalNumber(self):

python/tests/phonenumberutiltest.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,13 @@ def testNormaliseStripAlphaCharacters(self):
310310
phonenumbers.normalize_digits_only(inputNumber),
311311
msg="Conversion did not correctly remove alpha character")
312312

313+
def testNormaliseStripNonDiallableCharacters(self):
314+
inputNumber = "03*4-56&+a#234"
315+
expectedOutput = "03*456+234"
316+
self.assertEqual(expectedOutput,
317+
phonenumberutil._normalize_diallable_chars_only(inputNumber),
318+
msg="Conversion did not correctly remove non-diallable characters")
319+
313320
def testFormatUSNumber(self):
314321
self.assertEqual("650 253 0000", phonenumbers.format_number(US_NUMBER, PhoneNumberFormat.NATIONAL))
315322
self.assertEqual("+1 650 253 0000", phonenumbers.format_number(US_NUMBER, PhoneNumberFormat.INTERNATIONAL))

0 commit comments

Comments
 (0)