CREATE OR REPLACE PACKAGE xx_delimited_string
AS
-- p_str - the string to get the i'th word from
-- p_str can be xyz,yxz,zyx,zxy and you want to get the zxy as return ---- Value
-- p_n - the word to get from the string -- an index into the string
-- p_enclosed_by - what the words might be wrapped in. In the above -- -- example, chr(34) is a double quote
-- p_terminated_by - what separates the words. In the above example, ---- chr(44) is a comma.
FUNCTION nth_word(
p_str IN VARCHAR2
, p_n IN VARCHAR2
, p_enclosed_by IN VARCHAR2 DEFAULT ''''
, p_separated_by IN VARCHAR2 DEFAULT ','
)
RETURN VARCHAR2;
PRAGMA RESTRICT_REFERENCES(nth_word, WNDS, RNDS);
END xx_delimited_string;
/
CREATE OR REPLACE PACKAGE BODY xx_delimited_string
AS
TYPE vcarray IS TABLE OF VARCHAR2(2000)
INDEX BY BINARY_INTEGER;
g_words vcarray;
g_empty vcarray;
g_last_string VARCHAR2(4096);
FUNCTION de_quote(
p_str IN VARCHAR2
, p_enc_by IN VARCHAR2
)
RETURN VARCHAR2
IS
BEGIN
RETURN REPLACE(LTRIM(RTRIM(p_str
, p_enc_by
)
, p_enc_by
)
, p_enc_by || p_enc_by
, p_enc_by
);
END de_quote;
PROCEDURE parse_string(
p_str IN VARCHAR2
, p_delim IN VARCHAR2
, p_sep IN VARCHAR2
)
IS
l_n NUMBER DEFAULT 1;
l_in_quote BOOLEAN DEFAULT FALSE;
l_ch CHAR(1);
l_len NUMBER DEFAULT NVL(LENGTH(p_str)
, 0
);
BEGIN
IF (l_len = 0)
THEN
RETURN;
END IF;
g_words := g_empty;
g_words(1) := NULL;
FOR i IN 1 .. l_len
LOOP
l_ch := SUBSTR(p_str
, i
, 1
);
IF (l_ch = p_delim)
THEN
l_in_quote := NOT l_in_quote;
END IF;
IF ( l_ch = p_sep
AND NOT l_in_quote)
THEN
l_n := l_n + 1;
g_words(l_n) := NULL;
ELSE
g_words(l_n) := g_words(l_n) || l_ch;
END IF;
END LOOP;
FOR i IN 1 .. l_n
LOOP
g_words(i) := de_quote(g_words(i)
, p_delim
);
END LOOP;
END parse_string;
FUNCTION nth_word(
p_str IN VARCHAR2
, p_n IN VARCHAR2
, p_enclosed_by IN VARCHAR2 DEFAULT ''''
, p_separated_by IN VARCHAR2 DEFAULT ','
)
RETURN VARCHAR2
IS
BEGIN
IF ( g_last_string IS NULL
OR p_str <> g_last_string)
THEN
g_last_string := p_str;
parse_string(p_str
, p_enclosed_by
, p_separated_by
);
END IF;
RETURN g_words(p_n);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN NULL;
END nth_word;
END xx_delimited_string;
/
How to Test
SELECT xx_delimited_string.nth_word(:p_str
, 4
, CHR(34)
, CHR(44)
)
FROM DUAL
AS
-- p_str - the string to get the i'th word from
-- p_str can be xyz,yxz,zyx,zxy and you want to get the zxy as return ---- Value
-- p_n - the word to get from the string -- an index into the string
-- p_enclosed_by - what the words might be wrapped in. In the above -- -- example, chr(34) is a double quote
-- p_terminated_by - what separates the words. In the above example, ---- chr(44) is a comma.
FUNCTION nth_word(
p_str IN VARCHAR2
, p_n IN VARCHAR2
, p_enclosed_by IN VARCHAR2 DEFAULT ''''
, p_separated_by IN VARCHAR2 DEFAULT ','
)
RETURN VARCHAR2;
PRAGMA RESTRICT_REFERENCES(nth_word, WNDS, RNDS);
END xx_delimited_string;
/
CREATE OR REPLACE PACKAGE BODY xx_delimited_string
AS
TYPE vcarray IS TABLE OF VARCHAR2(2000)
INDEX BY BINARY_INTEGER;
g_words vcarray;
g_empty vcarray;
g_last_string VARCHAR2(4096);
FUNCTION de_quote(
p_str IN VARCHAR2
, p_enc_by IN VARCHAR2
)
RETURN VARCHAR2
IS
BEGIN
RETURN REPLACE(LTRIM(RTRIM(p_str
, p_enc_by
)
, p_enc_by
)
, p_enc_by || p_enc_by
, p_enc_by
);
END de_quote;
PROCEDURE parse_string(
p_str IN VARCHAR2
, p_delim IN VARCHAR2
, p_sep IN VARCHAR2
)
IS
l_n NUMBER DEFAULT 1;
l_in_quote BOOLEAN DEFAULT FALSE;
l_ch CHAR(1);
l_len NUMBER DEFAULT NVL(LENGTH(p_str)
, 0
);
BEGIN
IF (l_len = 0)
THEN
RETURN;
END IF;
g_words := g_empty;
g_words(1) := NULL;
FOR i IN 1 .. l_len
LOOP
l_ch := SUBSTR(p_str
, i
, 1
);
IF (l_ch = p_delim)
THEN
l_in_quote := NOT l_in_quote;
END IF;
IF ( l_ch = p_sep
AND NOT l_in_quote)
THEN
l_n := l_n + 1;
g_words(l_n) := NULL;
ELSE
g_words(l_n) := g_words(l_n) || l_ch;
END IF;
END LOOP;
FOR i IN 1 .. l_n
LOOP
g_words(i) := de_quote(g_words(i)
, p_delim
);
END LOOP;
END parse_string;
FUNCTION nth_word(
p_str IN VARCHAR2
, p_n IN VARCHAR2
, p_enclosed_by IN VARCHAR2 DEFAULT ''''
, p_separated_by IN VARCHAR2 DEFAULT ','
)
RETURN VARCHAR2
IS
BEGIN
IF ( g_last_string IS NULL
OR p_str <> g_last_string)
THEN
g_last_string := p_str;
parse_string(p_str
, p_enclosed_by
, p_separated_by
);
END IF;
RETURN g_words(p_n);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN NULL;
END nth_word;
END xx_delimited_string;
/
How to Test
SELECT xx_delimited_string.nth_word(:p_str
, 4
, CHR(34)
, CHR(44)
)
FROM DUAL
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.