Как извлечь группу из регулярного выражения в Oracle?

#sql #oracle

#sql #Oracle

Вопрос:

Я получил этот запрос и хочу извлечь значение между скобками.

 select de_desc, regexp_substr(de_desc, '[(. )]', 1)
from DATABASE
where col_name like '[%]';
  

Однако это дает мне значение в скобках, например «[TEST]». Я просто хочу «ПРОВЕРИТЬ». Как мне изменить запрос, чтобы получить его?

Ответ №1:

Третий параметр функции REGEXP_SUBSTR указывает позицию в целевой строке ( de_desc в вашем примере), с которой вы хотите начать поиск. Предполагая, что совпадение найдено в данной части строки, это не влияет на то, что возвращается.

В Oracle 11g для функции есть шестой параметр, который, я думаю, вы пытаетесь использовать, который указывает группу захвата, которую вы хотите вернуть. Примером правильного использования может быть:

 SELECT regexp_substr('abc[def]ghi', '[(. )]', 1,1,NULL,1) from dual;
  

Где последний параметр 1 указывает номер группы захвата, которую вы хотите вернуть. Вот ссылка на документацию, которая описывает параметр.

похоже, что в 10g нет этой опции, но в вашем случае вы можете добиться того же результата с помощью:

 select substr( match, 2, length(match)-2 ) from (
SELECT regexp_substr('abc[def]ghi', '[(. )]') match FROM dual
);
  

поскольку вы знаете, что совпадение будет иметь ровно один лишний символ в начале и в конце. (В качестве альтернативы вы можете использовать RTRIM и LTRIM для удаления скобок с обоих концов результата.)

Комментарии:

1. Что удивительно, так это то, что 6-й параметр не упоминается в официальной документации Oracle REGEXP_SUBSTR. Спасибо, что указали, что она существует.

2. Похоже, Google приведет вас к старой документации для REGEXP_SUBSTR, но если вы сможете найти документацию 11g, вы сможете увидеть 6-й параметр: docs.oracle.com/cd/B28359_01/server.111/b28286 /…

Ответ №2:

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

 select regexp_replace(de_desc, '.*[(. )].*', '1') from DATABASE;
  

Комментарии:

1. ИМХО, это самый простой, легко запоминающийся, более гибкий и, следовательно, лучший способ сделать это.

2. Я бы предупредил любого, кто использует REGEXP_REPLACE для получения группы захвата, что, если шаблон не соответствует, Oracle вернет все значение, тогда как поведение, которое вы, вероятно, хотите, чтобы оно возвращалось null . Например, REGEXP_REPLACE ('abcdefghi', '.*[(. )].*', '1') (шаблон не соответствует) возвращает abcdefghi . Это однажды сбило меня с толку.

3. Проблема здесь в том, что Oracle regexp не предоставляет функцию для возврата части строки, соответствующей группе захвата. Вы можете попробовать использовать рекурсивный запрос (выберите … из вкладки подключиться с помощью …), но будьте осторожны с потенциальной проблемой производительности.

4. Чтобы обойти проблему, о которой упоминает @Jared, вы можете выполнить захват «или все» |^.*$ . regexp_replace(de_desc, '.*[(. )].*|^.*$', '1') . Если в группе захвата 1 ничего не записано, то вся строка будет заменена на null .