【问题标题】:Regular expression recursive replace (increasing indentation)正则表达式递归替换(增加缩进)
【发布时间】:2020-11-30 22:28:05
【问题描述】:

我确信这应该是可能的,我想避免使用一个函数,因为它是一个页面上的一次性报告(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

在此先感谢

【问题讨论】:

  • 我认为单独使用正则表达式是不可能的。

标签: regex oracle oracle11g


【解决方案1】:

这有点,但有点工作(至少,我是如何理解这个问题的)。查看代码中的 cmets。

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

【讨论】:

    【解决方案2】:

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

    with rcte (id, value, lvl, result) as (
      select id, value, 1, regexp_substr(value, '(.*?)( - |$)', 1, 1, null, 1)
      from your_table
      union all
      select id, value, lvl + 1, regexp_substr(value, '(.*?)( - |$)', 1, lvl + 1, null, 1)
      from rcte
      where regexp_substr(value, '(.*?)( - |$)', 1, lvl + 1, null, 1) is not null
    )
    select id,
      listagg(case when lvl > 1 then rpad(chr(10), lvl, '>') || ' ' 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, value, lvl, result) as (
      select id, value, 1, regexp_substr(value, '(.*?)( - |$)', 1, 1, null, 1)
      from your_table
      union all
      select id, value, lvl + 1, regexp_substr(value, '(.*?)( - |$)', 1, lvl + 1, null, 1)
      from rcte
      where regexp_substr(value, '(.*?)( - |$)', 1, lvl + 1, null, 1) is not null
    )
    select id,
      listagg(case when lvl > 1 then rpad(' ', lvl, '>') || ' ' 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, value, lvl, result) as (
      select id, value, 1, regexp_substr(value, '(.*?)( - |$)', 1, 1, null, 1)
      from your_table
      union all
      select id, value, lvl + 1,
        rpad('>', lvl, '>') || ' ' || regexp_substr(value, '(.*?)( - |$)', 1, lvl + 1, null, 1)
      from rcte
      where regexp_substr(value, '(.*?)( - |$)', 1, lvl + 1, null, 1) is not null
    )
    select id,
      listagg(result, ' ') within group (order by lvl) as result
    from rcte
    group by id
    order by id;
    

    db<>fiddle

    【讨论】:

      猜你喜欢
      • 2011-03-12
      • 1970-01-01
      • 1970-01-01
      • 2011-10-28
      • 2012-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多