PL SQL 正则表达式子字符串

Posted

技术标签:

【中文标题】PL SQL 正则表达式子字符串【英文标题】:PL SQL regular expression substring 【发布时间】:2017-02-09 15:21:47 【问题描述】:

我的字符串很长。

message := 'I loooove my pet animal';

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

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

本质上它应该在前 15 个字符处找到整个单词的位置,然后将原始字符串分成 2 个。

请给我一些想法,我该怎么做。

谢谢。

【问题讨论】:

如果字符串长度为 50,你以两个长度为 25 的字符串结尾,可以吗? 不,我不能随意断词。我不需要打破一个完整的词。我需要用完整的单词分成2个字符串。 那么如果字符串是"You are Supercalifragilisticexpialidocious" 你想要拆分的地方呢?你分手了"You are" PL/SQL 是一种编程语言,所以使用循环:1) 获取前 16 个字符。 2)最后一个空白在哪里? 3) 拆分。 4) 取出字符串的其余部分并继续第 1 步,... litscape.com/words/length/16_letters/16_letter_words.html 【参考方案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.

【讨论】:

【参考方案2】:

首先是 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

输出

【讨论】:

i 作为 instr 的最后一个参数听起来不正确,将始终返回 0

以上是关于PL SQL 正则表达式子字符串的主要内容,如果未能解决你的问题,请参考以下文章

pl/sql 正则表达式验证

正则表达式背后的 pl/sql 否定查看

如何在 Pl/SQL 中编写正则表达式匹配模式?

在 oracle 中使用正则表达式查找 POBOX - PL/SQL

正则表达式 substr,起始位置位于字符串 PL/SQL 的末尾

替换 PL/SQL 中的几行正则表达式函数