PL SQL正则表达式子字符串

时间:2017-02-09 15:21:47

标签: regex oracle plsql substr

我有一个很长的字符串。

message := 'I loooove my pet animal';

这个字符串长23个字符。如果message大于15个字符,我需要找到message的长度,我可以将字符串分成2个字符串。例如,在这种情况下,

message1 := 'I loove my'
message2 := 'pet animal'

基本上它应该找到前一个到15个字符的整个单词的位置,并在那时将原始字符串分成2个。

请告诉我如何做到这一点。

谢谢。

2 个答案:

答案 0 :(得分:1)

这是一个通用的解决方案 - 可能有多个输入字符串,并且输入任意长度。唯一的假设是,没有一个单词可能超过15个字符,并且两个空格之间的所有内容都被视为单词。如果“单词”可以超过15个字符,则可以调整解决方案,但需求本身需要说明在这种情况下所需的结果是什么。

我在CTE(顶部)组成两个输入字符串 - 这不是解决方案的一部分,它只是用于测试和说明。我也用简单的SQL编写了这个 - 这类问题不需要PL / SQL代码。设置处理(而不是一次一行)应该可以更好地执行。

方法是识别所有空格的位置(我也为每个字符串追加并添加空格,因此我不必处理第一个和最后一个子字符串的异常);然后我在一个递归子查询中决定每个“最大”子串应该从哪里开始,它应该在哪里结束;然后输出子串是微不足道的。我使用了一个递归查询,它应该在Oracle 11.1中运行(或者使用我使用的语法的11.2,在CTE声明中使用列名 - 它可以很容易地在11.1中更改)。在Oracle 12中,使用MATCH_RECOGINZE重写相同的想法会更容易。

with
     inputs ( id, str ) as (
       select 101, 'I loooove my pet animal' from dual union all
       select 102, '1992 was a great year for - make something up here as needed' from dual
     ),
     positions ( id, pos ) as (
       select id, instr(' ' || str || ' ', ' ', 1, level)
       from   inputs
       connect by level <= length(str) - length(replace(str, ' ')) + 2
              and prior id = id
              and prior sys_guid() is not null
     ),
     r ( id, str, line_number, pos_from, pos_to ) as (
       select id, ' ' || str || ' ', 0, null, 1
         from inputs
       union all
       select r.id, r.str, r.line_number + 1, r.pos_to,
              ( select max(pos)
                from   positions 
                where id = r.id and pos - r.pos_to between 1 and 16
              )
         from r
         where pos_to is not null
     )
select id, line_number, substr(str, pos_from + 1, pos_to - pos_from - 1) as line_text
from   r
where  line_number > 0 and pos_to is not null
order by id, line_number
;

<强>输出

  ID LINE_NUMBER LINE_TEXT
---- ----------- ---------------
 101           1 I loooove my
 101           2 pet animal
 102           1 1992 was a
 102           2 great year for
 102           3 - make
 102           4 something up
 102           5 here as needed

7 rows selected.

答案 1 :(得分:0)

  • 首先是reverse字符串。

    SELECT REVERSE(strField) FROM DUAL;
    
  • 然后计算长度i = length(strField)

  • 然后找到中间的第一个空格

    j := INSTR( REVERSE(strField), ' ', i / 2,  i)`
    
  • 最后由i - j (maybe +/- 1 need to test it)

  • 分割

<强> DEMO

WITH parameter (id, strField) as (
    select 101, 'I loooove my pet animal' from dual union all
    select 102, '1992 was a great year for - make something up here as needed' from dual union all
    select 103, 'You are Supercalifragilisticexpialidocious' from dual  
), prepare (id, rev, len, middle) as (
    SELECT id, reverse(strField), length(strField), length(strField) / 2
    FROM parameter
)    
SELECT p.*, l.*, 
       SUBSTR(strField, 1, len -  INSTR(rev, ' ', middle)) as first, 
       SUBSTR(strField, len -  INSTR(rev, ' ', middle) + 2, len) as second
FROM parameter p
JOIN prepare l
  ON p.id = l.id

<强>输出

enter image description here