Форматировать номер телефона в Oracle с кодом страны

У меня есть требование форматировать номера телефонов следующим образом:

  • Нет пробелов
  • Нет специальных символов
  • Удалить предшествующий ноль - если существует код города
  • Удалите код страны, если он есть, например. +44

Например, это: (03069) 990927 станет: 3069990927.

До сих пор я пришел к этому:

replace(replace(replace(replace(replace(replace(substr(replace(ltrim([VALUE],0), ' ', ''),nvl(length(substr(replace(ltrim([VALUE],0), ' ', ''),11)),0)+1), '-', ''), '(', ''), ')', ''),'/', ''), '.', ''), '+', '')

Есть ли более короткая версия этого, возможно, с использованием регулярного выражения?

Окончательная версия этого фрагмента станет столбцом в представлении, которое вернет следующие столбцы:

  • Номер клиента
  • Имя Клиента
  • Страна
  • Отформатированный номер телефона

Отформатированный номер телефона будет объединен с международным телефонным кодом (например, +44), сохраненным в базе данных в таблице — DIALCODE_TAB(COUNTRY_CODE, CODE). Ниже приведен пример использования приведенного выше синтаксиса replace:

CREATE OR REPLACE FORCE VIEW "CUST_PHONE" ("CUSTOMER_ID", "NAME", "COUNTRY", "PHONE_NUMBER") AS 
  select 
    cicm.customer_id, 
    cicm.name, 
    dct.country, 
    dct.code || replace(replace(replace(replace(replace(replace(substr(replace(ltrim(cicm.value,0), ' ',   ''),nvl(length(substr(replace(ltrim(cicm.value,0), ' ', ''),11)),0)+1), '-', ''), '(', ''),   ')', ''),'/', ''), '.', ''), '+', '') phone_number 
from customer_info_comm_method cicm 
join dialcode_tab dct 
  on dct.country_code = customer_info_api.get_country_code(cicm.customer_id) 
where cicm.method_id_db = 'PHONE' 
  --and dct.code || replace(replace(replace(replace(replace(replace(substr(replace(ltrim(cicm.value,0), ' ',   ''),nvl(length(substr(replace(ltrim(cicm.value,0), ' ', ''),11)),0)+1), '-', ''), '(', ''),   ')', ''),'/', ''), '.', ''), '+', '') = [phone_number] 
--in terms of performance this SQL has to be written so that it returns all the records or a specific record when searching for the phone number - very quickly (<10s).
WITH read only;

Н.Б. Запись клиента может содержать более 1 номера телефона, и один и тот же номер телефона может существовать более чем в 1 записи клиента.


person pwlm    schedule 06.01.2014    source источник
comment
см. stackoverflow.com/questions/2947623/   -  person 72DFBF5B A0DF5BE9    schedule 06.01.2014
comment
Регулярное выражение, избавляющее от большей части шума, сработает; но насколько гибки форматы, с которых вы начинаете? Я предполагаю, что в значительной степени свободный текст. Это означает, что вам, возможно, придется удалить международные коды, прежде чем искать ведущие нули; и иметь дело как с нотацией +44, так и с эквивалентами для конкретной страны, например 001, чтобы звонить в США из Великобритании?   -  person Alex Poole    schedule 06.01.2014
comment
Это в основном правильно @Alex, за исключением того, что звонок всегда будет из Великобритании.   -  person pwlm    schedule 07.01.2014


Ответы (3)


Для начала замечание: это работает только в том случае, если страна хранится в другом месте для записи и нет телефонных номеров без кода города. В противном случае никто не сможет снова восстановить полный номер телефона.

Затем: как коды стран представлены в ваших данных? Всегда +44 или можно 0044? Будьте осторожны здесь. Особенно не удаляйте один ноль (при условии, что это код города), когда на самом деле это первый из двух нулей, представляющих код страны :-)

Затем: Вам нужен список всех кодов стран. Возьмем, к примеру, +1441441441. Где заканчивается код страны? (Решение: +1441 — это Бермудские острова.)

Что касается «без пробелов» и «без специальных символов», вы можете решить это лучше всего с помощью regexp_replace.

В общем, не такая простая задача, как вы, очевидно, ожидали. (Но это тоже не сложно сделать.)

Я бы использовал PL/SQL для этого.

Надеюсь, мои подсказки вам помогут. Удачи.

РЕДАКТИРОВАТЬ: Вот что нужно. Я все еще думаю, что здесь лучше всего подойдет функция PL/SQL.

Убедитесь, что ваш DIALCODE_TAB содержит все необходимые коды стран.

1. Trim the phone number.
2. Then check if its starts with a country identifyer (+, 00).
2.1. If so: remove that. Remove all non-digits. Look up the country code in your table and remove it.
2.2. If not so: check if it starts with an area identifyer (0).
2.2.1. If so: remove it.
2.2.2. In any case: remove all non-digits.

Это должно сделать это, если числа действительны. В Германии иногда люди пишут +49(0)40-123456, что неверно, поскольку в одном или используется код страны или код города, а не оба в одном и том же количество. (0) должен быть удален, чтобы сделать число действительным.

person Thorsten Kettner    schedule 06.01.2014
comment
Вы абсолютно правы @Thorsten. Я разверну свой вопрос дальше. - person pwlm; 07.01.2014
comment
Я расширил свой ответ соответственно. - person Thorsten Kettner; 09.01.2014

SELECT LTRIM(REGEXP_REPLACE(
                      REGEXP_REPLACE('+44(03069) 990927',
                                    '(\+).([[:digit:]])+'), -- to strip off country code
                     '[^[:alnum:]]'),-- Strip off non-aplanumeric [:digit] if only digit
             '0') -- Remove preceding Zero
FROM DUAL;

Не работает для +44990927 (если код страны заканчивается без пробела или чего-то еще, или страна не начинается с +)

person Maheswaran Ravisankar    schedule 06.01.2014

скрипт SQL

Настройка схемы Oracle 11g R2:

CREATE TABLE phone_numbers ( phone_number ) AS
          SELECT '(03069) 990927' FROM DUAL
UNION ALL SELECT '+44 1234 567890' FROM DUAL
UNION ALL SELECT '+44(0)1234 567890' FROM DUAL
UNION ALL SELECT '+44(012) 34-567-890' FROM DUAL
UNION ALL SELECT '+44-1234-567-890' FROM DUAL
UNION ALL SELECT '+358-1234567890' FROM DUAL;

Запрос 1:

Если вы имеете дело только с +44 международными телефонными кодами, вы можете:

  • используйте ^\+44|\D для удаления международного кода +44 и всех нецифровых символов; тогда
  • используйте ^0 для удаления ведущего нуля, если он присутствует.

Как это:

SELECT REGEXP_REPLACE(
         REGEXP_REPLACE(
           phone_number,
           '^\+44|\D',
           ''
         ),
         '^0', '' ) AS phone_number
FROM   phone_numbers

Результаты:

|  PHONE_NUMBER |
|---------------|
|    3069990927 |
|    1234567890 |
|    1234567890 |
|    1234567890 |
|    1234567890 |
| 3581234567890 |

(Вы можете видеть, что это не работает для последнего номера с международным кодом +358.)

Запрос 2:

Это можно упростить до одного регулярного выражения (это немного менее читабельно):

SELECT REGEXP_REPLACE(
         phone_number,
         '^(\+44)?\D*0?|\D',
         ''
       ) AS phone_number
FROM   phone_numbers

Результаты:

|  PHONE_NUMBER |
|---------------|
|    3069990927 |
|    1234567890 |
|    1234567890 |
|    1234567890 |
|    1234567890 |
| 3581234567890 |

Запрос 3:

Если вы хотите иметь дело с несколькими международными телефонными кодами, вам необходимо знать, какие из них действительны (см. http://en.wikipedia.org/wiki/List_of_country_calling_codes для списка).

Это пример регулярного выражения, которое удалит действительные международные телефонные коды, начинающиеся с +3, +4 или +5 (все остальные телефонные коды я оставлю вам для написания):

SELECT REGEXP_REPLACE(
         phone_number,
         '^(\+(3[0123469]|3[57]\d|38[01256789]|4[013456789]|42[013]|5[09]\d|5[12345678]))?\D*0?|\D',
         ''
       ) AS phone_number
FROM   phone_numbers

Результаты:

| PHONE_NUMBER |
|--------------|
|   3069990927 |
|   1234567890 |
|   1234567890 |
|   1234567890 |
|   1234567890 |
|   1234567890 |

Если + в начале международного телефонного кода не является обязательным, просто замените \+ (рядом с началом регулярного выражения) на \+?.

person MT0    schedule 06.01.2014