我已经编写了两个有效的函数,但我相信可能有更好(更快、更优雅)的方式,在 Oracle 中使用正则表达式。
这两个函数将在字符串中找到一个位置,该位置是 'n' 个单词之前,第二个函数会找到 'n' 个单词之后的位置。它们看起来像这样;
FUNCTION FIND_POS_WORD_N_BEFORE(IN_WORD_POS IN BINARY_INTEGER, NUMBER_OF_WORDS_BACK IN BINARY_INTEGER, IN_STRING IN VARCHAR2) RETURN BINARY_INTEGER DETERMINISTIC
IS
CURRENT_POS BINARY_INTEGER := 0;
LOOP_COUNT BINARY_INTEGER := 0;
OUT_POS BINARY_INTEGER := 0;
BEGIN
WHILE CURRENT_POS + 1 < IN_WORD_POS OR (LOOP_COUNT > 0 AND CURRENT_POS = 0)
LOOP
LOOP_COUNT := LOOP_COUNT + 1;
CURRENT_POS := INSTR(IN_STRING,' ',1,LOOP_COUNT);
IF LOOP_COUNT > NUMBER_OF_WORDS_BACK
THEN
OUT_POS := INSTR(IN_STRING,' ',1,LOOP_COUNT-NUMBER_OF_WORDS_BACK);
END IF;
END LOOP;
RETURN OUT_POS + 1;
END FIND_POS_WORD_N_BEFORE;
FUNCTION FIND_POS_WORD_N_AFTER(IN_WORD_END_POS IN BINARY_INTEGER, NUMBER_OF_WORDS_AFTER IN BINARY_INTEGER, IN_STRING IN VARCHAR2) RETURN BINARY_INTEGER DETERMINISTIC
IS
CURRENT_POS BINARY_INTEGER := IN_WORD_END_POS;
LOOP_COUNT BINARY_INTEGER := 0;
OUT_POS BINARY_INTEGER := LENGTH(IN_STRING);
BEGIN
WHILE (LOOP_COUNT < NUMBER_OF_WORDS_AFTER + 1)
LOOP
LOOP_COUNT := LOOP_COUNT + 1;
CURRENT_POS := INSTR(IN_STRING,' ',IN_WORD_END_POS,LOOP_COUNT) - 1;
END LOOP;
IF LOOP_COUNT >= NUMBER_OF_WORDS_AFTER AND CURRENT_POS != -1
THEN
OUT_POS := CURRENT_POS;
END IF;
RETURN OUT_POS;
END FIND_POS_WORD_N_AFTER;
您传入目标字符串的开始(或结束)位置,向后或向前多少个单词以及字符串。我会这样使用它;(为了便于阅读,我可能会将其分成多行)
SELECT SUBSTR(:test_string,FIND_POS_WORD_N_BEFORE(instr(:test_string,'moderately'), 3,:test_string),instr(:test_string,'moderately')-FIND_POS_WORD_N_BEFORE(instr(:test_string,'moderately'), 3,:test_string))
FROM dual;
其中 :test_string 是;
this is a test of a moderately long group of words
它会回来;
test of a
我希望有人对 Oracle regexp_substr 足够了解,可以将其编写为一行代码。