2016-05-06 3 views
1

Мне нужно создать функцию, которая примет вход stings любой длины и возвратит массив строк, каждый из которых содержит n длинных фрагментов. Например, ввод This is a test с 3 символов длинные куски должны вернуться:ORACLE PL-SQL как создать функцию для разделения строки и возврата n-long «кусков» в массив?

Thi 
s i 
s a 
tes 
t 

Я создал следующую функцию, чтобы сделать это. Мой вопрос в том, есть ли, возможно, лучший и быстрый способ приблизиться к этому? Я знаю, что эту функцию можно назвать много раз, используя очень длинные строки, и я не хочу этого замедлять работу системы. Кроме того, мне в конечном итоге необходимо настроить функцию так, чтобы она также создавала новую запись при обнаружении разделителя. Например, с «длиной отрезка» из трех:

Testing with comma delimiters, one, two, three, test

Если вернуться:

Tes 
tin 
g w 
ith 
co 
mma 
del 
imi 
ter 
s, 
one 
, 
two 
, 
thr 
ee, 
te 
st 

Обратите внимание, что я не хочу, разделитель самонастраивается быть удалены или заменены. У меня только что новая запись строки/нового массива заполняется сразу после обнаружения.

Вот мой код до сих пор:

CREATE OR REPLACE FUNCTION SPLIT_STRING (
    p_str VARCHAR2, --String to split 
    p_del VARCHAR2, --Delimiter 
    p_len INTEGER, --Length of each chunk 
    p_force NUMBER) --Forces split when length is reached (1=on, 0=off) 
RETURN VARCHAR2 IS 
    l_tmp_str VARCHAR2(32767); 
    l_chnk_len INTEGER; 
    l_str  VARCHAR2(32767); 
    l_chunk  VARCHAR2(32767); 
    l_pos  INTEGER; 
    l_len  INTEGER; 
    l_chnksize NUMBER; 
BEGIN 
    --Determine the strings total length 
    l_len:= LENGTH(p_str); 
    IF (l_len > 0) 
    THEN 
     l_tmp_str:= p_str; 

     --Determine the necessary number of chuncks 
     l_chnksize:=(l_len/p_len); 
     IF MOD(l_chnksize,1) != 0 
     THEN 
      l_chnksize:= CEIL(l_chnksize); 
     END IF; 

     --Split the string into chunks 
     IF p_force = 1 
     THEN 
      l_pos:=1;  
      FOR loop_num IN 1..l_chnksize 
      LOOP 
       IF (loop_num>1) 
       THEN 
        l_str:=l_str||CHR(10)||CHR(13)||SUBSTR(p_str,l_pos,p_len); 
       ELSE 
        l_str:=SUBSTR(p_str,l_pos,p_len); 
       END IF; 

       --Increment position placeholder 
       l_pos:=l_pos+p_len; 
      END LOOP; 
     ELSE 
      l_str:='UNFORCED, NOT IMPLEMENTED'; 
     END IF; 
    END IF; 

--Return the delimited string 
RETURN l_str; 

Мой конкретный вопрос: существует ли быстрый способ сделать это для большой строки входов?

+0

Вам не нужно беспокоиться о большой строке. Максимальный размер ввода - 32767. И я думаю, что выполнение этой функции займет менее 0,01 с для самого большого входа. –

ответ

1

Я не знаю, если это быстрее, но определенно проще. Вы фактически не кладете куски в массивы, а вставляете символ новой строки после каждого разделителя или группы символов. Это можно легко сделать с помощью регулярных выражений.

select regexp_replace('Testing with comhm,a sdfdeli,mitjers,one,two,three,test', 
         '(.{0,3},)|(.{5})', 
         '\1\2' ||chr(10))  chunks 
from dual; 

CHUNKS 
------- 
Testi 
ng wi 
th co 
mhm, 
a sdf 
deli, 
mitje 
rs, 
one, 
two, 
three 
, 
test 

Regex Пояснение: (. {0,3},)

  • : Группа до 3-х символов с последующим запятой (разделитель), предполагая, что 5 в качестве длина каждого куска.
  • (. {5}): Группа из 5 символов, считая 5 как длину каждого куска.

Эти первая и вторая группы захвата заменяются собой, добавленными символом новой строки.

Generic выражение будет,

'(.{0,'||(length-2)||'}'||delimiter||')|(.{'||(length)||'})' 
+0

Спасибо за ответ, это действительно работает. Интересно, что после модификации моего кода, чтобы делать ТОЧНО то же самое, что и ваше регулярное выражение, используя структуру LOOP, а не ваше регулярное выражение, и тестируя 10 000 раз в LOOP для строки длины 3000 Char, метод LOOP работает лучше. Я этого не ожидал. Тем не менее, спасибо. –

 Смежные вопросы

  • Нет связанных вопросов^_^