正则表达式递归替换增加缩进

问题描述

我确定应该可以,并且我想避免使用函数,因为它是页面上的一次性报告(Oracle 11g),但是我真的很想用缩进的换行符格式化以下字符串随后每次替换“-”以显示层次结构

例如:

This is the base level - This is level 2 - And this is the second

因此,我可以开始并用换行符替换“-”并应用CSS pre以确保它们全部在一行上

但理想情况下,我想要这样:

This is the base level
> This is level 2
>> And this is the second

非常感谢

解决方法

这有点像 ugly ,但是有点起作用(至少,我对这个问题的理解)。查看代码中的注释。

SQL> WITH test (col)
  2    -- Sample string
  3       AS (SELECT 'This is the base level - This is level 2 - And this is the second'
  4             FROM DUAL),5    -- Split it to rows (minus sign is a delimiter)
  6       temp
  7       AS (    SELECT LEVEL lvl,8                      TRIM (REGEXP_SUBSTR (col,9                                           '[^-]+',10                                           1,11                                           LEVEL))
 12                         val
 13                 FROM test
 14           CONNECT BY LEVEL <= REGEXP_COUNT (col,'-') + 1)
 15  -- join it back,using '>' along with CHR(10) as delimiter
 16  SELECT REPLACE (
 17            XMLAGG (XMLELEMENT (e,LPAD ('>',lvl - 1,'>') || val || CHR (10)) ORDER BY
 18                                                                                   lvl).EXTRACT (
 19               '//text()'),20            '&gt;',21            '>')
 22            result
 23    FROM temp;

RESULT
--------------------------------------------------------------------------------
This is the base level
>This is level 2
>>And this is the second


SQL>

如果您问“为什么XMLAGG而不是LISTAGG”,那是因为

 16  SELECT LISTAGG (val,'>')) WITHIN GROUP (ORDER BY lvl)
 17    FROM temp;
SELECT LISTAGG (val,'>')) WITHIN GROUP (ORDER BY lvl)
                                *
ERROR at line 16:
ORA-30496: Argument should be a constant.
,

如果在第一个参数内完成填充,则可以使用listagg

with rcte (id,value,lvl,result) as (
  select id,1,regexp_substr(value,'(.*?)( - |$)',null,1)
  from your_table
  union all
  select id,lvl + 1,1)
  from rcte
  where regexp_substr(value,1) is not null
)
select id,listagg(case when lvl > 1 then rpad(chr(10),'>') || ' ' end || result)
    within group (order by lvl) as result
from rcte
group by id
order by id;
ID | RESULT
-: | :--------------------------------------------------------------------------------
 1 | This is the base level
     > This is level 2
     >> And this is the second           
 2 | Base only                                                                        

但是你也说过

我可以开始并用换行符替换“-”并应用CSS pre以确保它们全部在一行上

因此,如果您只想换一行,就不能只添加换行符:

with rcte (id,listagg(case when lvl > 1 then rpad(' ','>') || ' ' end || result)
    within group (order by lvl) as result
from rcte
group by id
order by id;
ID | RESULT
-: | :-------------------------------------------------------------------------------
 1 | This is the base level > This is level 2 >> And this is the second              
 2 | Base only                                                                       

您还可以在递归CTE中添加>,这可能会更整洁:

with rcte (id,rpad('>','>') || ' ' || regexp_substr(value,listagg(result,' ') within group (order by lvl) as result
from rcte
group by id
order by id;

db<>fiddle