:: Не фоксом единым
Регулярные выражения в Oracle
Pekpytep
Автор

Сообщений: 727
Откуда: Луганск
Дата регистрации: 19.10.2010
Приветствую всех.
Есть экселевская таблица, загружаемая впоследствии в таблицу Oracle. Одно из полей содержит номер телефона, который может быть в виде +7 123 456 78 90, +7(123) 4567890, 8-123-456-78-90 и т.д. Пытаюсь причесать все номера к одному формату, содержащему исключительно цифры, используя regexp_replace().
Собственно, вопрос. Как удалить из строки пробелы, скобки, +, - и т.д. я понял, но только последовательно, цепочкой из нескольких regexp_replace(). Можно ли оставить в строке только цифры одним вызовом функции? Буду благодарен за готовый рецепт или хотя-бы подсказку.
Ratings: 0 negative/0 positive
Re: Регулярные выражения в Oracle
my

Сообщений: 206
Дата регистрации: 09.06.2006
regexlib точка com
regexlib.com
Ratings: 0 negative/0 positive
Re: Регулярные выражения в Oracle
Pekpytep
Автор

Сообщений: 727
Откуда: Луганск
Дата регистрации: 19.10.2010
Спасибо!
select regexp_replace('+7 (901)a 7W8.9r-77-z7,7', ('[+ ., a-z A-Z ()-]*'), '') from dual;
Такое выражение вроде отрабатывает как мне надо.
Ratings: 0 negative/0 positive
Re: Регулярные выражения в Oracle
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Проще надо быть
SELECT REGEXP_REPLACE('+7 (901)a 7W8.9r-77-z7,7', '[^[:digit:]]')
FROM DUAL;
убираем НЕ числа.
Есть ещё чуть менее наглядный, но точно такой же по сути вариант:
SELECT REGEXP_REPLACE('+7 (901)a 7W8.9r-77-z7,7', '\D') FROM DUAL;
\D это все не-числа, а \d это все числа, если что


------------------
WBR, Igor




Исправлено 2 раз(а). Последнее : Igor Korolyov, 14.12.16 11:53
Ratings: 0 negative/0 positive
Re: Регулярные выражения в Oracle
Pekpytep
Автор

Сообщений: 727
Откуда: Луганск
Дата регистрации: 19.10.2010
Давно не чувствовал себя так глупо...
Ratings: 0 negative/0 positive
Re: Регулярные выражения в Oracle
Pekpytep
Автор

Сообщений: 727
Откуда: Луганск
Дата регистрации: 19.10.2010
А как с помощью REGEXP_REPLACE оставить только цифры и десятичные разделители (.,) ?
Ratings: 0 negative/0 positive
Re: Регулярные выражения в Oracle
Pekpytep
Автор

Сообщений: 727
Откуда: Луганск
Дата регистрации: 19.10.2010
regexp_replace(rate, '[^[:digit:]*.,[:digit:]*]')
Вот так вроде работает, но не уверен что это корректный вариант.
Ratings: 0 negative/0 positive
Re: Регулярные выражения в Oracle
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Да вроде просто
REGEXP_REPLACE(RATE, '[^[:digit:].,]')


------------------
WBR, Igor




Исправлено 1 раз(а). Последнее : Igor Korolyov, 16.05.17 18:39
Ratings: 0 negative/0 positive
Re: Регулярные выражения в Oracle
Pekpytep
Автор

Сообщений: 727
Откуда: Луганск
Дата регистрации: 19.10.2010
"Просто" только для тех, кто глубоко вник, а мне они что-то никак не даются. Никак не усвою группировку выражений, в чем разница выражений для regexp_replace между "заменить то на это" и "убрать все кроме этого".
Ratings: 0 negative/0 positive
Re: Регулярные выражения в Oracle
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Не, я тут под "просто" имел в виду что у тебя много лишних буковок Внутри квадратных скобок "особое значение" имеют лишь символы ^[]-
"Крышка" - только в первой позиции. Закрывающая квадратная скобка - КРОМЕ первой позиции. Открывающая квадратная скобка - в зависимости от следующего символа начинает POSIX character class, POSIX collation element или POSIX character equivalence class. Минус задаёт диапазон, кроме случая когда он первый в строке, последний в строке, или стоит после другого минуса (являясь в этом случае "просто символом минуса").
Твой пример включает ещё и * как символ, ну и по два раза добавляет и звезду и цифры в этот самый "набор для исключения".

Если ты имел в виду шаблон "цифры, потом точка или запятая, потом снова цифры" то явно промахнулся. Да и REGEXP_REPLACE в этом виде не для того предназначен - он как раз ЗАМЕНЯЕТ найденный шаблон на нечто (если ничего в качестве замены не указано, как в этих примерах - удаляет его) а не БЕРЁТ то что подходит под шаблон выкидывая всё прочее.

REGEXP_SUBSTR() может вынимать из строки то что подходит под шаблон. Например из строки 'В 2017 году ВВП страны увеличится на 1.15% и составит 1,234млрд, что на 0,22млрд больше чем в 2016 году'. Можно последовательно (используя соответствующие параметры функции) вынуть числа 2017 1.15 1,234 0,22 2016
Но при помощи исходной функции "фильтрации нечисел" мы получим ОДНУ строку вида 20171.151,234,0,222016 что, наверное, не совсем правильно будет
Если ты хотел написать шаблон ищущий именно десятичное число (с одним из возможных разделителей) в строке, то нужен был бы шаблон примерно такого вида
'[[:digit:]]+((\.|,)[[:digit:]]+)?'
или то же самое, но короче за счёт применения \d вместо POSIX описания класса символов [:digit:], которые (такие "классы символов") должны быть всегда внутри квадратных скобок определяющих "набор символов".
'\d+((\.|,)\d+)?'
Если его рассматривать "по шагам":
1 \d+ ищем цифру встречающуюся 1 или более раз. Это "жадный" поиск - т.е. в поиск попадут ВСЕ цифры до тех пор пока не встретится "не цифра"
2 ( начало группы
3 ( начало вложенной группы
4 \.|, точка или запятая - точка экранируется, т.к. она не внутри "набора символов". Можно было тут вместо "группы с выбором" применить тот же "набор символов", написав вместо (\.|,) просто [.,]
5 ) конец вложенной группы - т.к. не задан квантификатор, то группа должна встретиться ровно 1 раз
6 \d+ ищем цифры встречающиеся 1 или более раз. Это "жадный" поиск - т.е. в поиск попадут ВСЕ цифры до тех пор пока не встретится "не цифра"
7 )? конец группы. Задан квантификатор "ноль или один" - т.е. ВСЯ эту группа (начиная с шага 2) является необязательной.

У этого выражения есть изъян - он "не понимает" числа записанного БЕЗ целой части. Скажем .1234 Точнее, он для такого числа "потеряет" десятичный разделитель, вернув только его дробную часть т.е. 1234 в данном случае.
Можно несколькими способами "исправить" такой недочёт. К примеру вот этим коротким, но немного "сложно понимаемым".
'(\d*[.,])?\d+'
Попробуй сам его "разобрать" по шагам, и понять почему он правильно находит и целые числа, и десятичные дроби, и дроби без целой части, и даже число в конце предложения (завершающееся точкой).


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Регулярные выражения в Oracle
Pekpytep
Автор

Сообщений: 727
Откуда: Луганск
Дата регистрации: 19.10.2010
Igor Korolyov
REGEXP_REPLACE в этом виде не для того предназначен - он как раз ЗАМЕНЯЕТ найденный шаблон на нечто (если ничего в качестве замены не указано, как в этих примерах - удаляет его) а не БЕРЁТ то что подходит под шаблон выкидывая всё прочее.
А эксперименты говорят о другом:
select regexp_replace('a1b2c3.d4e5', '[^[:digit:],.]') from dual;
Цитата:
Result: 123.45
select regexp_replace('a1b2c3.d4e5', '[[:digit:],.]') from dual;
Цитата:
Result: abcde
select regexp_replace('a1b2c3.d4e5', '^[:digit:],.') from dual;
Цитата:
Result: a1b2c3.d4e5
Для меня такое поведение совершенно не очевидно и я не понимаю зависимость между шаблоном и результатом, почему в одном случае удаляет "все кроме", во втором - удаляет по шаблону, в третьем - не делает ничего.

Igor Korolyov
Если ты хотел написать шаблон ищущий именно десятичное число (с одним из возможных разделителей) в строке, то нужен был бы шаблон примерно такого вида
'[[:digit:]]+((\.|,)[[:digit:]]+)?'
Целью было обработать десятичные числа при импорте из csv в БД, т.е. я хотел именно убрать из текстового поля ошибочно введенные символы кроме цифр и десятичных разделителей.
Ratings: 0 negative/0 positive
Re: Регулярные выражения в Oracle
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Pekpytep
Igor Korolyov
REGEXP_REPLACE в этом виде не для того предназначен - он как раз ЗАМЕНЯЕТ найденный шаблон на нечто (если ничего в качестве замены не указано, как в этих примерах - удаляет его) а не БЕРЁТ то что подходит под шаблон выкидывая всё прочее.
А эксперименты говорят о другом:
select regexp_replace('a1b2c3.d4e5', '[^[:digit:],.]') from dual;
Цитата:
Result: 123.45

1 [ начинается набор символов
2 ^ это набор символов "всё кроме"
3 [:digit:] posix класс десятичных цифр
4 ,. просто два символа
5 ] завершается набор символов

Итого - шаблон ищет все символы КРОМЕ десятичных цифр, точки и запятой.
Шаблон используется в функции regexp_replace, которая ЗАМЕНЯЕТ найденные вхождения на свой 3-й параметр. т.к. 3-го параметра не указано, то заменяет на путоту - т.е. по сути вырезает их из строки. Что останется в строке в итоге? Как раз десятичные цифры, точки и запятые. Есть в этом проблема? Да, если пытаться применить напрямую to_number к этой "очищенной строке". Т.к. во-первых для to_number нужно задать ОДНОЗНАЧНЫЙ разделитель, во-вторых он не сможет правильно разобрать строку вида "123.456.789" - т.е. где как минимум несколько разделителей будет, не говоря уж о том что они будут разными.

Pekpytep
select regexp_replace('a1b2c3.d4e5', '[[:digit:],.]') from dual;
Цитата:
Result: abcde

Шаблон отличается тем, что это "позитивный" набор символов. Не "всё кроме", а именно "то что подходит". Подходят цифры, точка и запятая. Т.к. шаблон применён в regexp_replace без 3-го параметра, то эти самые найденные символы и заменяются на пустоту.

Pekpytep
select regexp_replace('a1b2c3.d4e5', '^[:digit:],.') from dual;
Цитата:
Result: a1b2c3.d4e5

1 ^ символ не внутри квадратных скобок - он имеет специальное значение как "якорь начала строки". Т.е. такой шаблон будет проверять последующее выражение ТОЛЬКО в начальной позиции строки.
2 [:digit:] это НЕ posix класс символов (тот должен быть ВНУТРИ квадратных скобок), это ПРОСТО набор символов :digt - то что они повторяются роли не играет.
3 ,. это ПРОСТО два подряд идущих символа, которые должны находится строго после ОДНОГО символа подходящего под набор из шага 2 (т.к. набор идёт без квантификатора, что значит "ровно одно вхождение").

Итого: данный шаблон ищет набор из 3 символов :,. или d,. или i,. или g,. или t,. при том расположенный в начале строки. Т.к. шаблон применяется в regexp_replace без 3-го параметра, то в случае нахождения эти 3 символа будут удалены.
т.е.
select regexp_replace('d,.a1b2c3.d4e5', '^[:digit:],.') from dual;
--Результат 'a1b2c3.d4e5'

Pekpytep
Целью было обработать десятичные числа при импорте из csv в БД, т.е. я хотел именно убрать из текстового поля ошибочно введенные символы кроме цифр и десятичных разделителей.
И во что должен превратится текст
a1.b2.c3.d4e5
или
a1,b2.c3,d4e5
или просто
123,456.78
?


------------------
WBR, Igor




Исправлено 1 раз(а). Последнее : Igor Korolyov, 19.05.17 12:11
Ratings: 0 negative/0 positive
Re: Регулярные выражения в Oracle
Pekpytep
Автор

Сообщений: 727
Откуда: Луганск
Дата регистрации: 19.10.2010
Igor Korolyov
И во что должен превратится текст
a1.b2.c3.d4e5
или
a1,b2.c3,d4e5
или просто
123,456.78
?
Видимо, в
1.2.3.45
1,2.3,45
123,456.78

Я не ставлю себе целью написать на plsql искусственный интеллект или парсер всех возможных сортов говна, которое могут прислать на загрузку. Если я ожидаю на вход десятичное число, то примитивные опечатки я могу обработать, но остальное отправлю в некорректные записи.
Ratings: 0 negative/0 positive
Re: Регулярные выражения в Oracle
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Ну я имел в виду в какое ЧИСЛО это можно было бы превратить Ты же конвертируешь строки в даты, в числа - вот и вопрос возник, что с таким делать


------------------
WBR, Igor
Ratings: 0 negative/0 positive


Извините, только зарегистрированные пользователи могут оставлять сообщения в этом форуме.

On-line: 3 (Гостей: 3)

© 2000-2024 Fox Club 
Яндекс.Метрика