11--  TODO add support for https://datatracker.ietf.org/doc/html/rfc3966 (see https://habr.com/ru/post/278345/)
22
33create or replace  function  phone_normalize (
4-  country_code int ,
5-  area_code text ,
6-  local_number text 
4+  country_code int ,-- код страны в любом формате или NULL 
5+  area_code text ,-- код зоны в любом формате или NULL 
6+  local_number text -- локальный номер телефона в любом формате или NULL 
77)
88 returns text 
99 immutable
1010 -- returns null on null input
1111 parallel safe
1212 language plpgsql
13+  cost 10 
1314as 
1415$$
1516declare
1617 phone text ;
18+  is_starts_with_plus boolean ;
1719begin 
1820 --  not valid speed improves
1921 if country_code not between 0  and  999 
2325 return null ;
2426 end if;
2527
28+  is_starts_with_plus :=  country_code is null  and  concat_ws(' ' ' ^\D *?\+ ' 
29+ 2630 area_code :=  trim (regexp_replace(area_code, ' (?:^\D +|\D +$|[ ()\- .]+|&(?:ndash|minus);)' '  ' ' g' 
2731 local_number :=  trim (regexp_replace(local_number, ' (?:^\D +|\D +$|[ ()\- .]+|&(?:ndash|minus);)' '  ' ' g' 
2832
@@ -52,12 +56,14 @@ begin
5256 phone :=  replace(phone, ' /' ' ' 
5357 -- raise notice 'stage 2: %', phone;
5458
59+  /*  --DEPRECATED
5560 if phone ~ '(\d)1円{8}' --все цифры одинаковые 
5661 then 
5762 return null; 
5863 end if; 
64+  */  
5965
60-  if country_code is null  and  octet_length(phone) =  10 
66+  if country_code is null  and  octet_length(phone) =  10 and  not is_starts_with_plus 
6167 then
6268 phone =  ' 7' ||  phone;
6369 end if;
@@ -94,7 +100,7 @@ create or replace function phone_normalize(
94100 local_number text 
95101)
96102 returns text 
97-  stable 
103+  immutable 
98104 -- returns null on null input
99105 parallel safe
100106 language sql
@@ -111,13 +117,21 @@ create or replace function phone_normalize(
111117 phone text 
112118)
113119 returns text 
114-  stable 
120+  immutable 
115121 returns null  on  null  input
116122 parallel safe
117123 language sql
118124as 
119125$$
120-  select  phone_normalize(null , null , phone);
126+  select 
127+  case when -- speed improves: номер телефона в международном формате E.164 ?
128+  left(phone, 1 ) =  ' +' 
129+  and  octet_length(phone)
130+  between 1 /* +*/ +  8  -- https://stackoverflow.com/questions/14894899/what-is-the-minimum-length-of-a-valid-international-phone-number
131+  and  1 /* +*/ +  15  -- https://en.wikipedia.org/wiki/E.164 and https://en.wikipedia.org/wiki/Telephone_numbering_plan)
132+  and  phone ~ ' ^\+\d +$' 
133+  else phone_normalize(null , null , phone)
134+  end;
121135$$;
122136
123137
@@ -151,7 +165,12 @@ do $$
151165 assert phone_normalize(8 ,' 7 977' ' 123 45 67' =  ' +79771234567' 
152166 assert phone_normalize(7 ,' 977' ' 1234567' =  ' +79771234567' 
153167 assert phone_normalize(8 ,null ,' 8 9771234567' =  ' +79771234567' 
168+ 154169 assert phone_normalize(' 8 977 1234567' =  ' +79771234567' 
170+  assert phone_normalize(' +79771234567' =  ' +79771234567' 
171+  assert phone_normalize(' 677 1234567' =  ' +76771234567' 
172+  assert phone_normalize(' +677 1234567' =  ' +6771234567' 
173+  assert phone_normalize(' 210(-.-)7905(-.-)1234567' =  ' +21079051234567' 
155174
156175 -- negative
157176 assert phone_normalize(- 1 ,' 977' ' 1234567' null ;
0 commit comments