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 正则表达式子字符串的主要内容,如果未能解决你的问题,请参考以下文章
在 oracle 中使用正则表达式查找 POBOX - PL/SQL