0

我已经编写了两个有效的函数,但我相信可能有更好(更快、更优雅)的方式,在 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 足够了解,可以将其编写为一行代码。

4

2 回答 2

1

好的,我想我明白您想要什么:给定一个字符串,您指定一个位置或一个单词,并且您想要在该单词之后或之前预定义数量的单词。

让我们假设输入字符串:this is a test of a moderately long group of words. 我假设这些词只包含字母数字字符和下划线_。我假设单词用空格分隔。

警告:我认为您的函数将比使用正则表达式更有效。

案例一:词前

如果你想moderately在句子前面得到 3 个单词,那么你可以使用:

(?:\w+|\s){6}(?=moderately)
       ^^  ^^^   ^^^^^^^^^^^
       | double number| of words you need
       |              |
       |          the word you want to look before
      the separator, if there is more than one possible type of separator then
      put them in character class like this: [\s;REST_OF_SEPARATORS]

您可以使用 Oracle 的连接运算符或任何适当的方法在正则表达式字符串中插入单词数和要搜索的单词。

正则表达式 101 演示

案例二:词后

如果您想long在句子中紧随其后的 2 个单词,则可以使用:

(?<=long)(?:\w+|\s){4}

同样的事情,替换{4}为您输入的数字并替换long为您选择的单词。

正则表达式 101 演示

于 2013-09-05T14:51:50.113 回答
0

这将在所需单词之前和之后为您提供三个单词。

REGEXP_SUBSTR (source_string, '([^ ]+ +){3}moderately( +[^ ]+){3}')
于 2013-09-05T15:29:01.867 回答