Исключить серию символов в регулярном выражении через Oracle REGEXP_SUBSTR - PullRequest
0 голосов
/ 22 мая 2018

Я пытаюсь использовать Oracle REGEXP_SUBSTR для выбора полей в строке.

Пример:

this,,,is,,,an,,,example

Решение:

DECLARE
  field1 VARCHAR2(4000);
  field2 VARCHAR2(4000);
  field3 VARCHAR2(4000);
  field4 VARCHAR2(4000);
  separator VARCHAR2(300) := ',,,';
  lineToParse VARCHAR2(4000) := 'this,,,is,,,an,,,example';
BEGIN
  SELECT REGEXP_SUBSTR(lineToParse, '[^' || separator || ']+', 1, 1) AS part_1, REGEXP_SUBSTR(lineToParse, '[^' || separator || ']+', 1, 2) AS part_2, REGEXP_SUBSTR(lineToParse, '[^' || separator || ']+', 1, 3) AS part_3, REGEXP_SUBSTR(lineToParse, '[^' || separator || ']+', 1, 4) AS part_4
  INTO field1, field2, field3, field4
  FROM DUAL;
  DBMS_OUTPUT.PUT_LINE('Field 1: ' || field1);
  DBMS_OUTPUT.PUT_LINE('Field 2: ' || field2);
  DBMS_OUTPUT.PUT_LINE('Field 3: ' || field3);
  DBMS_OUTPUT.PUT_LINE('Field 4: ' || field4); 
END;

Это прекрасно работает длястрока выше, генерирующая:

Field 1: this
Field 2: is
Field 3: an
Field 4: example

Однако для приведенной ниже строки это не

this,,,is, a perfectly fine,,,new,,, line

Это потому, что вторая группа захвата должна быть: "это отлично"но в итоге получается "is".

Вывод:

Field 1: this
Field 2: is
Field 3:  a perfectly fine
Field 4: new

Причина в том, что я использую регулярное выражение:

[^,,,]+

Захватывает любой из символовкоторые следуют за ^ вместо последовательности.

Как я могу настроить свое регулярное выражение так, чтобы захватить всю последовательность?

Это должно быть совместимо с Oracle 11g.

Ответы [ 2 ]

0 голосов
/ 22 мая 2018

Просто измените свой вызов регулярного выражения на:

REGEXP_SUBSTR(lineToParse, '(.*?)(' || separator || '|$)', 1, 1, NULL, 1) AS part_1,

Это определяет группу символов, за которой следует группа, состоящая из вашего разделителя или конца строки.Он соответствует 1-му вхождению этой группы (4-й аргумент) и возвращает 1-ю группу (6-й аргумент).

Бонус! Эта форма регулярного выражения также обрабатывает элементы списка NULL, где форма '[^,]' не имеет!

Еще лучше, создайте функцию, которую вы можете поместить в пакет утилит для повторного использования, который инкапсулирует эту функцию.и называть это.Таким образом, люди, не знакомые с регулярным выражением, могут использовать его, и если изменение когда-либо потребуется, вам нужно всего лишь изменить код регулярного выражения:

FUNCTION  GET_LIST_ELEMENT(string_in VARCHAR2, element_in NUMBER, delimiter_in VARCHAR2 DEFAULT ',') RETURN VARCHAR2 IS
    BEGIN
      if string_in is null then
        return NULL;
      else
        RETURN REGEXP_SUBSTR(string_in, '(.*?)(\' || delimiter_in || '|$)', 1, element_in, NULL, 1);
      end if;
  END GET_LIST_ELEMENT;

Тогда ваш код будет выглядеть так:

util.get_list_element(lineToParse, 1, separator) AS part_1, 
util.get_list_element(lineToParse, 2, separator) AS part_2, 
util.get_list_element(lineToParse, 3, separator) AS part_3, 
util.get_list_element(lineToParse, 4, separator) AS part_4
0 голосов
/ 22 мая 2018

Я не думаю, что вы можете сделать простое регулярное выражение здесь.Во-первых, класс символов, который вы используете, [^,,,], ничем не отличается от [^,] - повторяющиеся символы, заключенные в квадратные скобки, не позволяют сопоставлять дублирующиеся символы в строке.Во-вторых, я не думаю, что отрицательное совпадение сработает, потому что регулярные выражения Oracle не поддерживают поиск.

Вы можете попробовать что-то вроде следующего:

SELECT REGEXP_SUBSTR(lineToParse, '.+?($|' || separator || ')', 1, 1) AS part_1
     , REGEXP_SUBSTR(lineToParse, '.+?($|' || separator || ')', 1, 2) AS part_2
     , REGEXP_SUBSTR(lineToParse, '.+?($|' || separator || ')', 1, 3) AS part_3
     , REGEXP_SUBSTR(lineToParse, '.+?($|' || separator || ')', 1, 4) AS part_4
  INTO field1, field2, field3, field4
  FROM DUAL;

Это все поможетлибо к разделителю, либо к концу линии нежадным способом.Теперь единственная проблема заключается в том, что возвращаемые значения могут включать разделители;Есть несколько способов избежать этого, самый простой из которых - использовать REPLACE(), но с Oracle 11 вы также можете использовать подвыражения с REGEXP_SUBSTR():

SELECT REGEXP_SUBSTR(lineToParse, '(.+?)($|' || separator || ')', 1, 1, 'c', 1) AS part_1
     , REGEXP_SUBSTR(lineToParse, '(.+?)($|' || separator || ')', 1, 2, 'c', 1) AS part_2
     , REGEXP_SUBSTR(lineToParse, '(.+?)($|' || separator || ')', 1, 3, 'c', 1) AS part_3
     , REGEXP_SUBSTR(lineToParse, '(.+?)($|' || separator || ')', 1, 4, 'c', 1) AS part_4
  INTO field1, field2, field3, field4
  FROM DUAL;

Однако, если начинается lineToParseс разделителем, вам все равно придется иметь дело с этим каким-то образом.Изменение первого экземпляра REGEXP_SUBSTR() на это, кажется, работает:

REGEXP_SUBSTR(lineToParse, '^(' || separator || ')?(.+?)($|' || separator || ')', 1, 1, 'c', 2) AS part_1

Надеюсь, это поможет.

...