Oracle - 需要在给定字符串之间提取文本

use*_*216 5 regex sql oracle plsql substring

示例 - 需要在"Begin begin"和"End end"之间提取所有内容.我试过这种方式:

with phrases as (
  select 'stackoverflow is awesome. Begin beginHello, World!End end It has everything!' as phrase
    from dual
         )
select regexp_replace(phrase
     , '([[:print:]]+Begin begin)([[:print:]]+)(End end[[:print:]]+)', '\2')
  from phrases
       ;
Run Code Online (Sandbox Code Playgroud)

结果:你好,世界!

但是,如果我的文本包含换行符,则会失败.任何提示如何修复此问题以允许提取包含新行的文本?

[编辑]它如何失败:

with phrases as (
  select 'stackoverflow is awesome. Begin beginHello, 
  World!End end It has everything!' as phrase
    from dual
         )
select regexp_replace(phrase
     , '([[:print:]]+Begin begin)([[:print:]]+)(End end[[:print:]]+)', '\2')
  from phrases
       ;
Run Code Online (Sandbox Code Playgroud)

结果:

stackoverflow很棒.开始吧你好,世界!结束它拥有一切!

应该:

你好,
世界!

[编辑]

另一个问题.我们来看看这个样本:

WITH phrases AS (
  SELECT 'stackoverflow is awesome. Begin beginHello,
 World!End end It has everything!End endTESTESTESTES' AS phrase
    FROM dual
)
SELECT REGEXP_REPLACE(phrase, '.+Begin begin(.+)End end.+', '\1', 1, 1, 'n')
  FROM phrases;
Run Code Online (Sandbox Code Playgroud)

结果:

你好,
世界!最终它拥有一切!

所以它匹配结束字符串的最后一次出现,这不是我想要的.子标签应该被激活到我的标签的第一次出现,因此结果应该是:

你好,
世界!

首先出现标签字符串后的所有内容都应该被忽略.有任何想法吗?

Dav*_*ber 6

我不熟悉POSIX [[:print:]]字符类,但我使用通配符使您的查询正常运行..您需要指定n匹配参数,REGEXP_REPLACE()以便.可以匹配换行符:

WITH phrases AS (
  SELECT 'stackoverflow is awesome. Begin beginHello,
 World!End end It has everything!' AS phrase
    FROM dual
)
SELECT REGEXP_REPLACE(phrase, '.+Begin begin(.+)End end.+', '\1', 1, 1, 'n')
  FROM phrases;
Run Code Online (Sandbox Code Playgroud)

我使用了\1反向引用,因为我没有看到需要从正则表达式中捕获其他组.如果在分隔符之前或之后没有任何内容,则使用*量词(而不是+)也可能是个好主意.如果要捕获所有组,则可以使用以下命令:

WITH phrases AS (
  SELECT 'stackoverflow is awesome. Begin beginHello,
 World!End end It has everything!' AS phrase
    FROM dual
)
SELECT REGEXP_REPLACE(phrase, '(.+Begin begin)(.+)(End end.+)', '\2', 1, 1, 'n')
  FROM phrases;
Run Code Online (Sandbox Code Playgroud)

更新 - 仅供参考,我测试过[[:print:]],它不起作用.这并不奇怪,因为[[:print:]]它应该匹配可打印的字符.它与ASCII值低于32(空格)的任何内容都不匹配.你需要使用..

更新#2 - 每次更新问题 - 我认为正则表达式不会像你想要的那样工作.添加延迟量词(.+)没有效果,Oracle正则表达式没有前瞻性.您可能会做一些事情,一个是使用INSTR()SUBSTR():

WITH phrases AS (
  SELECT 'stackoverflow is awesome. Begin beginHello,
 World!End end It has everything!End endTESTTESTTEST' AS phrase
    FROM dual
)
SELECT SUBSTR(phrase, str_start, str_end - str_start) FROM (
    SELECT INSTR(phrase, 'Begin begin') + LENGTH('Begin begin') AS str_start
         , INSTR(phrase, 'End end') AS str_end, phrase
      FROM phrases
);
Run Code Online (Sandbox Code Playgroud)

另一种是结合INSTR()SUBSTR()使用正则表达式:

WITH phrases AS (
  SELECT 'stackoverflow is awesome. Begin beginHello,
 World!End end It has everything!End endTESTTESTTEST' AS phrase
    FROM dual
)
SELECT REGEXP_REPLACE(SUBSTR(phrase, 1, INSTR(phrase, 'End end') + LENGTH('End end')), '.+Begin begin(.+)End end.+', '\1', 1, 1, 'n')
  FROM phrases;
Run Code Online (Sandbox Code Playgroud)


Ste*_*han 2

试试这个正则表达式:

([[:print:]]+Begin begin)(.+?)(End end[[:print:]]+)
Run Code Online (Sandbox Code Playgroud)

使用示例:

SELECT regexp_replace(
         phrase ,
         '([[:print:]]+Begin begin)(.+?)(End end[[:print:]]+)',
         '\2',
         1,  -- Start at the beginning of the phrase
         0,  -- Replace ALL occurences
         'n' -- Let dot meta character matches new line character
)
FROM
  (SELECT 'stackoverflow is awesome. Begin beginHello, '
    || chr(10)
    || ' World!End end It has everything!' AS phrase
  FROM DUAL
  )
Run Code Online (Sandbox Code Playgroud)

点元字符 ( .) 匹配数据库字符集中的任何字符和换行符。但是,当调用 regexp_replace 时,match_parameter 必须包含n用于匹配新行的开关dot