powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Пятничные телефонные маски
30 сообщений из 30, показаны все 2 страниц
Пятничные телефонные маски
    #39532110
slow brain
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добрый день. Столкнулся тут с задачкой, выношу на суд общественности

Есть некая система, которая работает с телефонными номерами. Система позволяет задвать маску для поля.
В записи маски используются следующие правила:
9 - на этом месте указывается цифра

\<символ> - константный символ
Таким образом, для телефона РФ маска может быть записана в виде
Код: plaintext
\+\7\(999\)999\-99\-99 или 999\-999\-99\-99 или \9\-\8\-9999999999\; 

Задача 1 - запросом отформатировать сохраненные телефонные номера по маске. Запрос должен работать для произвольной маски, записанной по правилам (рассматриваем только номера РФ, записанные в формате 10 цифр, например, 4959009876 или 8005554212, корректность маски и проверять не нужно - это обеспечивает система)

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
SQL>   with m as (select '\+\7\(999\)999\-99\-99' mask, '4959009876' num from dual)
...
...
...
 14  select phone_num from (
...
 16  );

PHONE_NUM
--------------------------------------------------------------------------------
+7(495)900-98-76



Задача 2 - запросом убрать маску с номеров, записанных в формате маски (система передает номера в соответствии с маской, проверять на корректность не требуется - т.е. +7(495)900-98-76 преобразовать в 4959009876). Запрос так же должен работать для произвольной маски.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
SQL>   with m as (select '\+\7\(999\)999\-99\-99' mask, '+7(495)900-98-76' phone_num from dual)
...
...
...
 10  select num from (
...
 12  );

NUM
--------------------------------------------------------------------------------
4959009876

SQL>
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532122
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
slow brainЗадача 2
Код: plsql
1.
2.
3.
4.
5.
select regexp_substr(regexp_replace('+7(495)900-98-76', '\D'), '\d{10}$') as n from dual;

N
----------
4959009876
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532134
slow brain
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Elic,
красиво, но если добрый пользователь вколотит маску с цифровой константой на конце - не сработает
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
SQL>   with m as (select '\+\7\(999\)999\-99\-99\;\1' mask, '+7(495)900-98-76;1' phone_num from dual)
..
..
..
 10  select num from (
...
 12);

NUM
--------------------------------------------------------------------------------
4959009876
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532145
Фотография AmKad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
slow brainElic,
красиво, но если добрый пользователь вколотит маску с цифровой константой на конце - не сработает
Но ведь ты сказал, что маски всего три и корректность введенного телефона проверяется "системой".
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532154
slow brain
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
slow brainЗапрос должен работать для произвольной маски, записанной по правилам
То что я привел - это лишь примеры, этим фантазия не ограничивается.

По задаче 2 кстати я нашел два разных варианта. regexp есть в обоих, но они принципиально разные
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532162
slow brain
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AmKadНо ведь ты сказал, что маски всего три и корректность введенного телефона проверяется "системой".
корректность в том, что не требуется проверять синтаксис маски на корректность, а так же
в задаче 1 не требуется проверять число значащих позиций в маске и в номере - они совпадают (если не совпадает, оно отбрасывается ранее)

в задаче 2 не требуется проверять совпадение входных данных с маской - как раз это и обеспечивает система.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532170
Фотография AmKad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
slow brain,

Нужно четкое и непротиворечивое описание как и что парсить. И примеры. Лично я пока ничего не понял .
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532181
slow brain
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AmKad,
мне показалось что описано нормально.
Суть - номер записанный как 10 цифр отобразить в виде, задающемся маской, и наоборот, если номер записан по маске, включая разные доп. символы (в т.ч. они могут быть цифровыми и в произвольных местах) - эти доп.символы убрать. В маске символ "9" обозначает позицию цифры, экранирующий \ обозначает символ, следующий за ним, как есть. Маска может быть произвольной абсолютно, но должна записываться по правилам (т.е. любой символ не являющийся "9" экранируется, "9" может быть заэкранирована)
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532199
slow brain
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Примеры:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
 with m as (select '999\-999\-99\-99' mask, '4959009876' num from dual)
..
select phone_num from (              
);

495-900-98-76

with m as (select '\9\-\8\-9999999999\;' mask, '4959009876' num from dual)
..
select phone_num from (              
);

9-8-4959009876;

with m as (select '\+\7\(999\)999\-99\-99\;\1' mask, '4959009876' num from dual)
..
select phone_num from (              
);

+7(495)900-98-76;1


В обратную сторону думаю понятно.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532282
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
slow brainElic,
красиво, но если добрый пользователь вколотит маску с цифровой константой на конце - не сработает


Задачу нужно озвучивать внятно. Да и непонятно с какого бодуна цифры будут использоваться как разделители. Ну да ладно. Если число групп <= 9:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
with m as (
           select '999\-999\-99\-99' mask, '495-900-98-76' phone_num from dual union all
           select '\9\-\8\-9999999999\;' mask, '9-8-4959009876;' phone_num from dual union all
           select '\+\7\(999\)999\-99\-99\;\1' mask, '+7(495)900-98-76;1' phone_num from dual
          )
select  mask,
        phone_num,
        regexp_replace(
                       phone_num,
                       regexp_replace(regexp_replace(mask,'\\.','.'),'9+','(\d+)'),
                       '\1\2\3\4\5\6\7\8\9'
                      ) num
  from  m
/

MASK                       PHONE_NUM            NUM
-------------------------- -------------------- ----------
999\-999\-99\-99           495-900-98-76        4959009876
\9\-\8\-9999999999\;       9-8-4959009876;      4959009876
\+\7\(999\)999\-99\-99\;\1 +7(495)900-98-76;1   4959009876

SQL> 



SY.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532308
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
slow brainЗадача 2Думаю из-за ограничений оракловых регулярок без разбиения строки в том или ином виде не решается для числа групп девяток более 9.

Соотвественно, либо посимвольное разбиение либо выдирание групп девяток из исходного номера подшаманив над маской.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
SQL> with m as
  2  (select 1 id, '\+\7\(999\)999\-99\-99' mask, '+7(495)900-98-76' phone_num from dual
  3  union all select 2 id, '\+\7\(999\)999\-99\-99\;\1' mask, '+7(495)900-98-76;1' phone_num from dual
  4  )
  5  select *
  6  from m
  7  model
  8  partition by (id)
  9  dimension by (1 dummy)
 10  measures (replace(mask, '\') mask, phone_num, cast(null as varchar2(240)) result)
 11  rules iterate(1e9) until (substr(mask[1], iteration_number + 1, 1) is null)
 12  (
 13    result[1] = decode(substr(mask[1], iteration_number + 1, 1), '9',
 14                       result[1] || substr(phone_num[1], iteration_number + 1, 1), result[1])
 15  );

        ID      DUMMY MASK                       PHONE_NUM          RESULT
---------- ---------- -------------------------- ------------------ --------------------
         1          1 +7(999)999-99-99           +7(495)900-98-76   4959009876
         2          1 +7(999)999-99-99;1         +7(495)900-98-76;1 4959009876

SQL> with m as
  2  (select 1 id, '\+\7\(999\)999\-99\-99' mask, '+7(495)900-98-76' phone_num from dual
  3  union all select 2 id, '\+\7\(999\)999\-99\-99\;\1' mask, '+7(495)900-98-76;1' phone_num from dual
  4  )
  5  select id,
  6         listagg(regexp_substr(phone_num_mod, mask_mod, 1, 1, null, level)) within group (order by level) result
  7    from (select id,
  8                 translate(phone_num, '()', '##') phone_num_mod,
  9                 regexp_replace(regexp_replace(translate(mask, '()\', '##'), '(9+)', '(\1)'), '[^()]', '.') mask_mod
 10            from m)
 11  connect by prior id = id and level <= regexp_count(mask_mod, '\(') and prior sys_guid() is not null
 12  group by id;

        ID RESULT
---------- --------------------
         1 4959009876
         2 4959009876
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532331
slow brain
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Со второй задачей почти разобрались

способ №2 - чисто на regexp (я его сделал позже способа №1) - влоб с подсчетом количества групп

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
  with m as (select '\+\7\(999\)999\-99\-99\-\1' mask, '+7(495)900-98-76-1' phone_num from dual)
     , fmt1 as (select phone_num, replace(replace(regexp_replace(mask, '\\.','.'),'9','(\d)'),')(') mask_str from m)
     , fmt as (select phone_num
                    , mask_str
                    , listagg(txt,'') within group(order by txt) format_str
                 from fmt1
                    , (select '\'||rownum txt from fmt1 connect by level <= regexp_count(mask_str,'\(')) 
                group by phone_num, mask_str
               )
select num from (               
select regexp_replace(phone_num, mask_str, format_str) num from fmt);  



А отсюда и до решения задачи 1 недалеко

dbms_photoshopДумаю из-за ограничений оракловых регулярок без разбиения строки в том или ином виде не решается для числа групп девяток более 9.
Это был способ №1 - я его придумал раньше - просто вспомнив что поняте "маска" может трактоваться как "битовая маска" - и он не имеет ограчиней на группы
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
  with m as (
           select '999\-999\-99\-99' mask, '495-900-98-76' phone_num from dual union all
           select '\9\-\8\-9999999999\;' mask, '9-8-4959009876;' phone_num from dual union all
           select '\+\7\(999\)999\-99\-99\;\1' mask, '+7(495)900-98-76;1' phone_num from dual
          )
select  mask,
        phone_num,
        replace(utl_raw.cast_to_varchar2(utl_raw.bit_and(utl_raw.cast_to_raw(phone_num),utl_raw.cast_to_raw(replace(regexp_replace(mask, '\\.',chr(0)),'9',chr(255))))), chr(0)) 
    from m
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532344
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
slow brainчисто на regexpразрезать и склеить значит "чисто на regexp"?

Как уже было сказано, из-за ограничений оракловых регулярок для общего случая надо резать и клеить,
в результате чего натягивание этого алгоритма на SQL не более чем баловство.

Использование встроенных PL/SQL пакетов для RAW - тоже просто замыливание глаз.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532385
slow brain
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Свое решение по задаче №1 я опубликую в понедельник.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532412
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
#1 в лоб :)

Не решал пока вариант c '\\', финальный replace можно заменить каким-нибудь хитрым регекспом.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
with mask (id, mask, num) as (
  select 1, '999\-999\-99\-99', '4959009876' from dual
  union all
  select 2, '\+\7\(999\)999\-99\-99\;\1', '4959009876' from dual
  union all
  select 3, '\9\-\8\-9999999999\;', '4959009876' from dual
),
parse(id, mask, num, lvl, msk) as (
  select 
    id, mask, num, 1, regexp_replace(mask, '9{1}', substr(num, 1, 1), instr(replace(mask, '\9', '\x'), '9', 1, 1), 1) msk
  from mask m
  union all
  select 
    m.id, m.mask, m.num, p.lvl+1, regexp_replace(p.msk, '9{1}', substr(m.num, p.lvl+1, 1), instr(replace(m.mask, '\9', '\x'), '9', 1, p.lvl+1), 1) msk 
  from parse p
  join mask m on m.id = p.id and p.lvl+1 <= length(m.num)
)
select 
  mask, num, replace(msk, '\', '') as result
from parse
where lvl = length(num);
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532448
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
slow brainСо второй задачей почти разобрались

способ №2 - чисто на regexp (я его сделал позже способа №1) - влоб с подсчетом количества групп

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
  with m as (select '\+\7\(999\)999\-99\-99\-\1' mask, '+7(495)900-98-76-1' phone_num from dual)
     , fmt1 as (select phone_num, replace(replace(regexp_replace(mask, '\\.','.'),'9','(\d)'),')(') mask_str from m)
     , fmt as (select phone_num
                    , mask_str
                    , listagg(txt,'') within group(order by txt) format_str
                 from fmt1
                    , (select '\'||rownum txt from fmt1 connect by level <= regexp_count(mask_str,'\(')) 
                group by phone_num, mask_str
               )
select num from (               
select regexp_replace(phone_num, mask_str, format_str) num from fmt);  





Ты слишком усложнил - весь этот listagg совершенно не нужeн. Ссылка на несуществующий backreference замещается NULL, так-что достаточно '\1\2\3\4\5\6\7\8\9'. И группы из одной цифры создавать тоже ненужно - их ведь может быть всего 9.
Используй не (9) --> (\d) a (9+) --> (\d+) как в моем примере:

Код: plsql
1.
2.
3.
4.
5.
        regexp_replace(
                       phone_num,
                       regexp_replace(regexp_replace(mask,'\\.','.'),'9+','(\d+)'),
                       '\1\2\3\4\5\6\7\8\9'
                      ) num



SY.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532469
slow brain
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SY,
Именно твой вариант я бы запустил, если бы задачу внезапно не сняли :)

rpovarov, слишком перегружено.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532503
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
slow brainСвое решение по задаче №1 я опубликую в понедельник.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
with m as (
           select '999\-999\-99\-99' mask, '4959009876' num from dual union all
           select '\9\-\8\-9999999999\;' mask, '4959009876' num from dual union all
           select '\+\7\(999\)999\-99\-99\;\1' mask, '4959009876' num from dual
          ),
    r(
      mask,
      num,
      phone_num,
      mask_pos,
      num_pos
     ) as (
            select  mask,
                    num,
                    null phone_num,
                    0 mask_pos,
                    0 num_pos
              from  m
           union all
            select  mask,
                    num,
                    case substr(mask,mask_pos + 1,1)
                      when '\' then phone_num || substr(mask,mask_pos + 2,1)
                      else phone_num || substr(num,num_pos + 1,1)
                    end phone_num,
                    case substr(mask,mask_pos + 1,1)
                      when '\' then mask_pos + 2
                      else mask_pos + 1
                    end mask_pos,
                    case substr(mask,mask_pos + 1,1)
                      when '\' then num_pos
                      else num_pos + 1
                    end num_pos
              from  r
              where mask_pos < length(mask)
          )
select  mask,
        num,
        phone_num
  from  r
  where mask_pos = length(mask)
/

MASK                       NUM        PHONE_NUM
-------------------------- ---------- --------------------
999\-999\-99\-99           4959009876 495-900-98-76
\9\-\8\-9999999999\;       4959009876 9-8-4959009876;
\+\7\(999\)999\-99\-99\;\1 4959009876 +7(495)900-98-76;1

SQL> 



SY.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532510
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SY,

А с какой целью публикуется сие?
Я понимаю rpovarov может оттачивает мастерство с rec with, но в вашем случае в чем смысл?

Если на SQL идет попытка натянуть не SQL задачу так давайте это сделаем еще самым бредовым способом?
Если у нас есть 10 млн масок по 15 символов так давайте запихаем в workarea 150 млн строк и будем по ним бегать.
Затем фильтранем набор последней итерации.
Зато SQL.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532579
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshopЕсли у нас есть 10 млн масок по 15 символов так давайте запихаем в workarea 150 млн строк и будем по ним бегать.


Ну а почему ты решил что "10 млн масок"? Их может быть весьма ограниченное количество. И вызываться это будет например только когда клиент зашел на сайт чтобы показать его номер в привычной для географии клиента форме. Хотя согласен, хранить и номер и "отмаскированный" номер более разумно.

SY.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532584
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
имхо тут только в лоб (баловался не глядя других постов кроме стартового):
задача 1:
вариант 1
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
with m as (select '\+\7\(999\)999\-99\-99' mask, '4959009876' num from dual)
select
  regexp_replace(
     regexp_replace(
          mask
         ,'9(\\.)*9(\\.)*9(\\.)*9(\\.)*9(\\.)*9(\\.)*9(\\.)*9(\\.)*9(\\.)*9$'
         ,  substr(num,1,1)||'\1'
          ||substr(num,2,1)||'\2'
          ||substr(num,3,1)||'\3'
          ||substr(num,4,1)||'\4'
          ||substr(num,5,1)||'\5'
          ||substr(num,6,1)||'\6'
          ||substr(num,7,1)||'\7'
          ||substr(num,8,1)||'\8'
          ||substr(num,9,1)||'\9'
          ||substr(num,10,1)
       )
  ,'\\(.)','\1')
from m;


вариант 2
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
with m as (select '\+\7\(999\)999\-99\-99' mask, '4959009876' num from dual)
select
 m.*
 ,regexp_replace(
     (select 
        listagg(
           regexp_replace(
              regexp_substr(mask,'(\\.)*9',1,11-level)
             ,'((\\.)*)(9)','\1'||substr(num,11-level,1)
           )
        )within group( order by level desc)
      from dual
      connect by level<=10)
     ,'\\(.)','\1'
  )
from m

с to_char
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
with m as (select '\+\7\(999\)999\-99\-99' mask, '4959009876' num from dual)
select
 m.*
 ,regexp_replace(
     (select 
        listagg(
           to_char(
             to_date(1000+substr(num,11-level,1),'yyyy')
            ,regexp_replace(
               regexp_substr(mask,'(\\.)*9',1,11-level)
              ,'((\\.)*)9','"\1"y'
             )
           )
        )within group( order by level desc)
      from dual
      connect by level<=10)
     ,'\\(.)','\1'
  )
from m;

c utl_lms гораздо проще
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
with function format_number(p_mask in varchar2,p_num varchar2) return varchar2 
     as
     begin 
       return 
         regexp_replace(
           utl_lms.format_message(
             regexp_replace(p_mask,'(\\.)*9','\1%s')
            ,substr(p_num, 1,1)
            ,substr(p_num, 2,1)
            ,substr(p_num, 3,1)
            ,substr(p_num, 4,1)
            ,substr(p_num, 5,1)
            ,substr(p_num, 6,1)
            ,substr(p_num, 7,1)
            ,substr(p_num, 8,1)
            ,substr(p_num, 9,1)
            ,substr(p_num,10,1)
          )
        ,'\\(.)'
        ,'\1'
       ); 
     end format_number;
  m as (select '\+\7\(999\)999\-99\-99' mask, '4959009876' num from dual)
select
   m.*
  ,format_number(mask,num)
from  m

...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532656
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
dbms_photoshopSY,
Я понимаю rpovarov может оттачивает мастерство с rec with

Именно так. Балуюсь, пятничное же :)

IMHO такие вещи надо вообще убирать из базы, пусть frontend (или какой другой потребитель) сам конвертирует. Или жёстко ограничивать на количество знаков, чтобы работали решения, которые показали SY и xtender. И потом бить ногами любого, кто придёт с идеей менять количество позиций.

У меня на задания типа "...рассматриваем только номера РФ, записанные в формате 10 цифр..." срабатывает внутренний сигнал тревоги, потому что после подготовки красивого и элегантного решения с вероятностью 90% приходит вводная "формат может быть от 8 до 12 цифр". И надо переделывать, иногда полностью. Это не шпилька в сторону автора темы, просто из опыта работы.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532971
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Решение №1 с помощью MODEL (за образец взял код dbms_photoshop).
- обрабатываются '\9' и '\\' (временной заменой на "непечатные" символы)
- произвольное количество знаков (само собой, номер должен соответствовать маске)

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
with m(id, mask, phone_num) as
(
  select 1, '999\-999\-99\-99', '4959009876' from dual
  union all
  select 2, '\+\7\(999\)999\-99\-99\;\1', '4959009876' from dual
  union all
  select 3, '\9\-\8\-9999999999\;', '4959009876' from dual
  union all
  select 4, '\9\-\8\-9999999999999\;', '4959009876123' from dual
  union all
  select 5, '\\\9\-\8\-9999999\;', '4959009' from dual
  union all
  select 6, 'Типа номер и всё такое: \9\-\8\-9999999\;', '4959009' from dual
  )
select 
    id, mask, phone_num, replace(replace(result, chr(254), '9'), chr(255), '\') as result
from m
model
    partition by (id)
    dimension by (0 dummy)
    measures (mask, replace(replace(replace(mask, '\9', chr(254)), '\\', chr(255)), '\') mask_filtered, phone_num, cast(null as varchar2(240)) result)
    rules iterate(1e9) until (substr(phone_num[0], iteration_number+2, 1) is null)
    (
        result[0] = regexp_replace(decode(iteration_number, 0, mask_filtered[0], result[0]), 
                                    '9', 
                                    substr(phone_num[0], iteration_number+1, 1), 
                                    instr(mask_filtered[0], '9', 1, iteration_number+1), 
                                    1
                                    )
    )
order by id;    


        ID MASK                                                        PHONE_NUM     RESULT                                                                                                                                                                                                                                          
---------- ----------------------------------------------------------- ------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
         1 999\-999\-99\-99                                            4959009876    495-900-98-76                                                                                                                                                                                                                                   
         2 \+\7\(999\)999\-99\-99\;\1                                  4959009876    +7(495)900-98-76;1                                                                                                                                                                                                                              
         3 \9\-\8\-9999999999\;                                        4959009876    9-8-4959009876;                                                                                                                                                                                                                                 
         4 \9\-\8\-9999999999999\;                                     4959009876123 9-8-4959009876123;                                                                                                                                                                                                                              
         5 \\\9\-\8\-9999999\;                                         4959009       \9-8-4959009;                                                                                                                                                                                                                                   
         6 Типа номер и всё такое: \9\-\8\-9999999\;                   4959009       Типа номер и всё такое: 9-8-4959009;        
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39532977
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
rpovarov,

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
with m(id, mask, phone_num) as
(
  select 1, '\\9999999', '4959009' from dual
  )
select 
    id, mask, phone_num, replace(replace(result, chr(254), '9'), chr(255), '\') as result
from m
model
    partition by (id)
    dimension by (0 dummy)
    measures (mask, replace(replace(replace(mask, '\9', chr(254)), '\\', chr(255)), '\') mask_filtered, phone_num, cast(null as varchar2(240)) result)
    rules iterate(1e9) until (substr(phone_num[0], iteration_number+2, 1) is null)
    (
        result[0] = regexp_replace(decode(iteration_number, 0, mask_filtered[0], result[0]), 
                                    '9', 
                                    substr(phone_num[0], iteration_number+1, 1), 
                                    instr(mask_filtered[0], '9', 1, iteration_number+1), 
                                    1
                                    )
    )
order by id;    
ORA-01428: argument '0' is out of range
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39533032
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
xtender,

Точно, спасибо. Надо поменять очерёдность // и /9.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
with m(id, mask, phone_num) as
(
  select 1, '\\9999999', '4959009' from dual
  )
select 
    id, mask, phone_num, replace(replace(result, chr(254), '9'), chr(255), '\') as result
from m
model
    partition by (id)
    dimension by (0 dummy)
    measures (mask, replace(replace(replace(mask, '\\', chr(255)), '\9', chr(254)), '\') mask_filtered, phone_num, cast(null as varchar2(240)) result)
    rules iterate(1e9) until (substr(phone_num[0], iteration_number+2, 1) is null)
    (
        result[0] = regexp_replace(decode(iteration_number, 0, mask_filtered[0], result[0]), 
                                    '9', 
                                    substr(phone_num[0], iteration_number+1, 1), 
                                    instr(mask_filtered[0], '9', 1, iteration_number+1), 
                                    1
                                    )
    )
order by id;    

        ID MASK      PHONE_N RESULT                                                                                                                                                                                                                                          
---------- --------- ------- -------------------------
         1 \\9999999 4959009 \4959009   

...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39533048
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
rpovarov,

да что-то ты перемудрил... так проще:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
with m(id, mask, phone_num) as
(
  select 1, '\\999-99-99', '4951234' from dual
  union all
  select 6, 'Типа номер и всё такое: \9\-\8\-9999999\;', '4959009' from dual
  )
select 
    id, mask, phone_num, regexp_replace(result,'\\(.)','\1') result
from m
model
    dimension by (id)
    measures (mask, phone_num, regexp_replace(mask,'((\\.)*)9','\1'||chr(1)) result)
    rules iterate(15) -- тут тупо максимальную длину номера указать
    (
        result[any] = regexp_replace(result[cv()]
                                    ,chr(1)
                                    ,substr(phone_num[cv()], iteration_number+1,1)
                                    ,1,1
                                    )
    )
order by id;

...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39533059
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
xtender,
Красиво :) Пойду курить документацию по MODEL.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39533202
slow brain
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Всем доброе утро.

xtender, варианты "в лоб" не работают для шаблона с экранированным символом в конце (\+\7\(999\)999\-99\-99\;). Модель - работает.

Мой вариант: (добавил строки с комментарием относительно исходного однострочного)
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
 with m as (
   select '999\-999\-99\-99' mask, '4959009876' num from dual union all
           select '\9\-\8\-9999999999\;' mask, '4959009876' num from dual union all
           select '\+\7\(999\)999\-99\-99\;\1', '4959009876' num from dual)
     , m1 as (select num, replace(mask, '\9','\'||chr(1)) mask from m)
     , fmt as (select num
                    , rtrim(ltrim(replace(regexp_replace(' '||m1.mask, '(^9|[^9]|$)+',')('),'9','.'),')'),'(') mask_str
                    , listagg(txt,'') within group(order by lvl) format_str
                 from m1
                    , (select level lvl
                            , mask --для нескольких строк источника
                            , replace(replace(ltrim(regexp_substr(' '||mask,'(^9|[^9])+',1, level),'\9'),chr(1),'9'),'\')||'\'||level txt
                         from m1
                      connect by regexp_substr(' '||mask,'(^9|[^9])+',1, level) is not null 
                        and mask=prior mask and prior dbms_random.value is not null --для нескольких строк источника
                      ) a
                where m1.mask = a.mask --для нескольких строк источника
                group by m1.mask, num
              )
select phone_num from (              
select regexp_replace(num, mask_str, format_str) phone_num from fmt)
;



Принявшим участие - огромное спасибо.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39533207
rpovarov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
slow brainМой вариант: (добавил строки с комментарием относительно исходного однострочного)


"...и эти люди мне запрещали копаться в носу..." :)
rpovarov, слишком перегружено.
...
Рейтинг: 0 / 0
Пятничные телефонные маски
    #39533276
Фотография Sayan Malakshinov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
slow brain,

По коду видно что не будет у тебя работать на \\9.
...
Рейтинг: 0 / 0
30 сообщений из 30, показаны все 2 страниц
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Пятничные телефонные маски
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]