регулярное выражение в оракуле

Как получить нужные мне данные в Oracle, используя REGEXP_SUBSTR

SPRINTMVNO_PM_CDR_IWIRELESS_20121110_0813.csv get '08'in last four digits
RK_IPDR_RKMSG2_0043722_DT_20121113162710.txt  get '0043722' in the middle(between'_')
wireless_201211120015_201211120515            get '0515' (last four digits)

Я пробовал много раз, но некоторые выражения отлично работают в PHP или другом языке, но не работают в ORACLE. Возможно, синтаксис другой.

Например: второй я могу использовать /(?<=_)[0-9]*(?=_)/ для получения числа в php, но это не работает в Oracle.
Я пробовал

SELECT REGEXP_SUBSTR('RK_IPDR_RKMSG2_0043722_DT_20121113162710.txt','(?<=_)[0-9]*(?=_)') 
  FROM dual;

Нет выхода. Так что это не проблема двух косых черт

Альтернативной формулировкой этого вопроса может быть «как получить содержимое между символом или начать с него, но не включать его, с помощью регулярного выражения Oracle?»

Я знаю, что могу легко получить эти данные с помощью строковых функций, проблема в том, что нужно обрабатывать множество разных строк, каждая из которых имеет разные данные для извлечения. Итак, я хочу сохранить шаблоны в базе данных и использовать один regexp_substr для получения всех данных. В противном случае мне нужно жестко закодировать эти правила.


person Frank    schedule 17.11.2012    source источник
comment
Можете объяснить, какие правила вы пытаетесь применить? Вы представляете три строки, каждая из которых имеет разные выходные данные. Предположительно, вам нужны три разных шаблона поиска.   -  person APC    schedule 17.11.2012
comment
Похоже, ваш вопрос заключается в том, как я могу получить неслучайные строки из регулярного выражения, когда размер, расположение и значение этих строк полностью случайны?   -  person Ben    schedule 17.11.2012
comment
@APC Да, я хочу, чтобы три разных шаблона находили конкретные данные из этих трех строк. Для каждого примера, который мне нужно найти, будет больше похожих строк. Например: rk_ipdr_rkmsg2_00437222_dt_20121113162710.txt Эта строка может иметь другие похожие, такие как rk_ipdr_rkmsg2_0043724_dt_20121113162712.txt; rk_ipdr_rkmsg2_0043725_dt_201211111111111111111111111111111111111111111111111111111111111111111111111111111111111н.   -  person Frank    schedule 18.11.2012
comment
@Ben Извините, что ввел вас в заблуждение, это три отдельные группы строк.   -  person Frank    schedule 18.11.2012
comment
Каков ваш вариант использования? Вы получаете случайную строку и применяете все эти шаблоны, чтобы увидеть, какой из них соответствует? Вы получаете кучу строк и применяете только один шаблон, чтобы увидеть, какой из них соответствует? Или какая-то другая перестановка? Какие объемы данных вы обрабатываете за один поиск? И какая версия базы?   -  person APC    schedule 18.11.2012
comment
@APC Хорошо, пожалуйста, игнорируйте случаи, мне просто нужно решение, как получить содержимое между символом или начать с него, но не включать его, с регулярным выражением Oracle? например, строка: abcdaasdf_33621252_as545_1236 возвращает число между «_», но не включает «_». Спасибо   -  person Frank    schedule 18.11.2012


Ответы (3)


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

Например, чтобы найти первые два символа после последнего символа подчеркивания в строке, используйте SUBSTR() и INSTR() следующим образом:

with t as (select 'SPRINTMVNO_PM_CDR_IWIRELESS_20121110_0813.csv' str from dual)
select substr(str, instr(str, '_', -1)+1, 2)
from t
/

Обратите внимание, что вызов INSTR() имеет отрицательное смещение, чтобы начать отсчет с конца. Получение последних четырех символов строки использует тот же трюк:

with t as (select 'iwireless_201211120015_201211120515' str from dual)
select substr(str, -4)
from t
/

Самый простой способ определить шаблон подчеркивания, за которым следуют цифры, за которыми следует подчеркивание, — это регулярное выражение, но мы можем использовать TRIM(), чтобы удалить символы подчеркивания из результата.

with t as (select 'RK_IPDR_RKMSG2_0043722_DT_20121113162710.txt' str from dual)
select trim('_' from regexp_substr(str, '_([0-9]+)_'))
from t
/

Вот скрипт SQL, чтобы доказать, что эти методы работают.

Oracle имеет широкий набор функций, которые описаны в документации. Подробнее.


"пожалуйста, игнорируйте случаи, мне просто нужно решение этого "как получить содержимое между символом или начать с него, но не включать его, с регулярным выражением Oracle?"

Существует способ исключить символы из начала или конца результата, а именно разбить шаблон поиска на подвыражения. Это будет работать для предоставленной вами строки, потому что мы можем отделить начальные и конечные символы подчеркивания от требуемых чисел. К сожалению, параметр подвыражения имеет значение . последний параметр в подписи REGEXP_SUBSTR(), а поскольку функции SQL не принимают именованные параметры, это означает, что мы должны явно передавать значения по умолчанию для всех остальных параметров.

В любом случае, этот вызов вернет второе подвыражение, которое является искомой строкой, 0043722:

with t as (select 'RK_IPDR_RKMSG2_0043722_DT_20121113162710.txt' str from dual)
select regexp_substr(str, '(_)([0-9]+)(_)', 1,1,'i',2)
from t
/

Варианты использования действительно имеют значение. Функции REGEXP работают медленнее, чем их более простые эквиваленты. В 10gR2 REGEXP_SUBSTR() как минимум на порядок медленнее, чем SUBSTR(). Разница заметна при поиске большого количества строк и наносит вред, когда это число достигает миллионов (раскрытие: недавняя боль).

person APC    schedule 17.11.2012
comment
Я знаю, что могу легко получить эти данные с помощью строковых функций, проблема в том, что нужно обрабатывать множество разных строк, каждая из которых имеет разные данные для извлечения, поэтому я хочу сохранить шаблоны в базе данных и использовать один regexp_substr для получения все данные. В противном случае мне нужно жестко закодировать эти правила, это не очень хорошее решение. - person Frank; 18.11.2012
comment
Ты такой терпеливый, приятель. Спасибо за ваше решение. trim('' from regexp_substr(str, '_([0-9]+)')) это вдохновляет меня, что мне просто нужно добавить эту функцию обрезки в мой код, чтобы избежать всех '_' - person Frank; 19.11.2012

Начальная и конечная косые черты вокруг вашего регулярного выражения не имеют ничего общего с регулярным выражением.

Они являются артефактом языка perl/javascript.

Попробуйте без косой черты

person Bohemian♦    schedule 17.11.2012
comment
Я попробовал SELECT REGEXP_SUBSTR('RK_IPDR_RKMSG2_0043722_DT_20121113162710.txt','(?‹=_)[0-9]*(?=_)') FROM dual, без вывода. - person Frank; 17.11.2012

Oracle использует POSIX ERE (расширенные регулярные выражения) с заметным исключением, заключающимся в добавлении обратных ссылок. Но POSIX ERE очень ограничен — требуется совсем немного. Попробуйте использовать следующие регулярные выражения:

/([0-9]{2}80|[0-9]80[0-9]|80[0-9]{2})$/

Это даст вам 80 в последних четырех цифрах.

/0515$/

Это даст вам 0515 в качестве последних четырех цифр.

Я никогда не использовал Oracle, поэтому не знаю, нужны ли вам разделители, но эти два будут работать. Со средним немного сложнее. Если вы можете жить только с «да, это там», вы должны быть в состоянии уйти с

/_0043722_/

Но если вам нужно извлечь его, вы сможете найти какую-нибудь функцию обрезки, которая позволит вам указать, что нужно обрезать. Вы не можете сделать это с помощью регулярных выражений в Oracle.

О, и если вам нужно объединить все три в одно регулярное выражение:

/([0-9]{2}80|[0-9]80[0-9]|80[0-9]{2}|0515)$|_0043722_/

И если вам понадобится ссылка на регулярное выражение в будущем, попробуйте этот сайт.

person FrankieTheKneeMan    schedule 17.11.2012
comment
Эти строки являются просто примерами, числа генерируются динамически, и я хочу их извлечь. Спасибо за ваш ответ в любом случае. - person Frank; 17.11.2012