Регулярное выражение для REGEXP_SUBSTR в Oracle

У меня есть следующий текст для поиска:

#S7Z OK
#Wed Feb 18 07:16:26 GMT 2015
expiration=10.0
lastModified=1424192425832
length=466472
path=/name/_master_/563/5638ad54-8079-4399-ba2b-3257b6e6c7fd.pdf 
userType=

Слова, стоящие перед каждым =, являются именами свойств. Для каждого имени свойства я хотел бы получить значение свойства. Это означает, что я ищу регулярное выражение для использования с regexp_substr для получения значения каждого известного свойства.

Что-то вроде этого:

SELECT REGEXP_SUBSTR(
'#S7Z OK
#Wed Feb 18 07:16:26 GMT 2015
expiration=10.0
lastModified=1424192425832
length=466472
path=/name/_master_/563/5638ad54-8079-4399-ba2b-3257b6e6c7fd.pdf 
userType=',
'path=.+')
FROM dual

который возвращает: path=/name/master/563/5638ad54-8079-4399-ba2b-3257b6e6c7fd.pdf

Но мне нужно только значение, то есть "/name/master/563/5638ad54-8079-4399-ba2b-3257b6e6c7fd.pdf". Он также должен работать для истечения срока действия, lastModified и т. д., то есть я хочу искать не просто URL-адрес, а любое значение.

Как я могу добиться этого в одном регулярном выражении?


person amishelli    schedule 18.02.2015    source источник


Ответы (3)


'. +=' в качестве второго аргумента '' в качестве третьего аргумента

person dabal    schedule 18.02.2015

Вот как вы можете захватить все пары name=value одновременно. Обратите внимание, что я использую явный квантификатор {1,10} в регулярном выражении, чтобы предотвратить катастрофический возврат. (Это конкретное регулярное выражение может на самом деле не подпадать под это, и в этом случае вы можете заменить явный квантификатор на +. Но лучше не рисковать!)

WITH s1 AS (
    SELECT '#S7Z OK
#Wed Feb 18 07:16:26 GMT 2015
expiration=10.0
lastModified=1424192425832
length=466472
path=/name/_master_/563/5638ad54-8079-4399-ba2b-3257b6e6c7fd.pdf 
userType=' AS str
      FROM dual
)
SELECT SUBSTR(name_value, 1, INSTR(name_value, '=') - 1) AS myname
     , SUBSTR(name_value, INSTR(name_value, '=') + 1, LENGTH(name_value)) AS myvalue
  FROM (
    SELECT REGEXP_SUBSTR(REGEXP_SUBSTR(s1.str,'(\S+=\S*\s*){1,10}'), '\S+', 1, LEVEL) AS name_value
      FROM s1
   CONNECT BY REGEXP_SUBSTR(REGEXP_SUBSTR(s1.str,'(\S+=\S*\s*){1,10}'), '\S+', 1, LEVEL) IS NOT NULL
);

Вывод следующим образом:

MYNAME       | MYVALUE
-------------------------------------------------------------------------
expiration   | 10.0
lastModified | 1424192425832
length       | 466472
path         | /name/_master_/563/5638ad54-8079-4399-ba2b-3257b6e6c7fd.pdf
userType     | (null)

Пожалуйста, смотрите SQL Fiddle здесь.

Обратите внимание, что я мог бы использовать REGEXP_SUBSTR(name_value, '^[^=]+') и т. д. во внешнем запросе, но я полагал, что в этом запросе достаточно регулярных выражений (это немного дорого, я уверен, что SUBSTR() плюс INSTR() дешевле!). Также обратите внимание, что если вы используете Oracle 11g или выше, предложение CONNECT BY можно заменить следующим:

CONNECT BY LEVEL <= REGEXP_COUNT(REGEXP_SUBSTR(s1.str,'(\S+=\S*\s*){1,10}'), '\S+')

см. исправленную скрипту SQL.

person David Faber    schedule 19.02.2015

person    schedule
comment
Хороший - хотя обратите внимание, что это будет работать только в Oracle 11g + в соответствии с тем, что я нашел. - person James S; 18.02.2015
comment
спасибо, это работает отлично, и это было очень быстро! - person amishelli; 18.02.2015