Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Пятничные телефонные маски / 25 сообщений из 30, страница 1 из 2
06.10.2017, 12:43
    #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
06.10.2017, 12:54
    #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
06.10.2017, 13:03
    #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
06.10.2017, 13:12
    #39532145
AmKad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пятничные телефонные маски
slow brainElic,
красиво, но если добрый пользователь вколотит маску с цифровой константой на конце - не сработает
Но ведь ты сказал, что маски всего три и корректность введенного телефона проверяется "системой".
...
Рейтинг: 0 / 0
06.10.2017, 13:16
    #39532154
slow brain
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пятничные телефонные маски
slow brainЗапрос должен работать для произвольной маски, записанной по правилам
То что я привел - это лишь примеры, этим фантазия не ограничивается.

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

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

Нужно четкое и непротиворечивое описание как и что парсить. И примеры. Лично я пока ничего не понял .
...
Рейтинг: 0 / 0
06.10.2017, 13:41
    #39532181
slow brain
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пятничные телефонные маски
AmKad,
мне показалось что описано нормально.
Суть - номер записанный как 10 цифр отобразить в виде, задающемся маской, и наоборот, если номер записан по маске, включая разные доп. символы (в т.ч. они могут быть цифровыми и в произвольных местах) - эти доп.символы убрать. В маске символ "9" обозначает позицию цифры, экранирующий \ обозначает символ, следующий за ним, как есть. Маска может быть произвольной абсолютно, но должна записываться по правилам (т.е. любой символ не являющийся "9" экранируется, "9" может быть заэкранирована)
...
Рейтинг: 0 / 0
06.10.2017, 13:51
    #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
06.10.2017, 14:54
    #39532282
SY
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
06.10.2017, 15:15
    #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
06.10.2017, 15:38
    #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
06.10.2017, 15:48
    #39532344
dbms_photoshop
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пятничные телефонные маски
slow brainчисто на regexpразрезать и склеить значит "чисто на regexp"?

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

Использование встроенных PL/SQL пакетов для RAW - тоже просто замыливание глаз.
...
Рейтинг: 0 / 0
06.10.2017, 16:52
    #39532385
slow brain
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пятничные телефонные маски
Свое решение по задаче №1 я опубликую в понедельник.
...
Рейтинг: 0 / 0
06.10.2017, 17:31
    #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
06.10.2017, 18:13
    #39532448
SY
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
06.10.2017, 18:53
    #39532469
slow brain
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пятничные телефонные маски
SY,
Именно твой вариант я бы запустил, если бы задачу внезапно не сняли :)

rpovarov, слишком перегружено.
...
Рейтинг: 0 / 0
06.10.2017, 20:29
    #39532503
SY
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
06.10.2017, 21:03
    #39532510
dbms_photoshop
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пятничные телефонные маски
SY,

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

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


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

SY.
...
Рейтинг: 0 / 0
07.10.2017, 03:53
    #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
07.10.2017, 13:01
    #39532656
rpovarov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пятничные телефонные маски
dbms_photoshopSY,
Я понимаю rpovarov может оттачивает мастерство с rec with

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

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

У меня на задания типа "...рассматриваем только номера РФ, записанные в формате 10 цифр..." срабатывает внутренний сигнал тревоги, потому что после подготовки красивого и элегантного решения с вероятностью 90% приходит вводная "формат может быть от 8 до 12 цифр". И надо переделывать, иногда полностью. Это не шпилька в сторону автора темы, просто из опыта работы.
...
Рейтинг: 0 / 0
08.10.2017, 17:36
    #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
08.10.2017, 17:45
    #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
08.10.2017, 19:13
    #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
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Пятничные телефонные маски / 25 сообщений из 30, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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