Почему это регулярное выражение выполняет частичные совпадения? - PullRequest
0 голосов
/ 18 мая 2018

У меня есть следующие необработанные данные:

1.1.2.2.4.4.4.5.5.9.11.15.16.16.19 ...

Я использую это регулярное выражение для удаления дубликатов:

([^.]+)(.[ ]*\1)+

, что приводит к следующему:

1.2.4.5.9.115.16.19 ...

Проблема в том, как регулярное выражение обрабатывает 1.1 в подстроке .11.15. То, что должно быть 9.11.15.16, становится 9.115.16.Как это исправить?

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

Регулярное выражение используется в Oracle REGEXP_REPLACE

Десятичная дробь - это разделитель.Я пробовал запятые и трубы, но это не решает проблему.

Ответы [ 4 ]

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

Сгруппируйте повторяющийся шаблон и удалите его

Как указало revo, большой источник ваших трудностей возник из-за того, что вы не избежали периода.Кроме того, результирующая строка, включающая 115, может быть объяснена следующим образом (Valdi_Bo ранее сделала подобное наблюдение):

([^.]+)(.[ ]*\1)+ будет соответствовать 11.15 следующим образом:

SCOTT@DB>SELECT
  2      '11.15' val,
  3      regexp_replace('11.15','([^.]+)(\.[ ]*\1)+','\1') deduplicated
  4  FROM
  5      dual;
VAL     DEDUPLICATED
11.15   115

Вот аналогичный подход для решения этих проблем:

составление сопоставления с шаблоном

- поиск списка сопоставления без периодов длиной от 0 до N (подвыражениессылается на \1).

'19 ', что соответствует ([^.]*)

-Ищите повторы, которые образуют наш второй список соответствия, связанный с подвыражением 2, на который ссылается \2.

'19 .19.19', что соответствует ([^.]*)([.]\1)+

-Ищите точку или конец строки.Это список совпадений, на который ссылается \3.Это исправляет совпадение «11 .15» на «115».

([.]|$)

строка замены

Я заменяю шаблон соответствия заменойСтрока, состоящая из первого экземпляра списка сопоставления без периодов.

\1\3

Решение

regexp_replace(val,'([^.]*)([.]\1)+([.]|$)','\1\3')

Вот пример использованиянекоторые варианты ваших примеров:

SCOTT@db>WITH tst AS (
  2      SELECT
  3          '1.1.2.2.4.4.4.5.5.9.11.15.16.16.19' val
  4      FROM
  5          dual
  6      UNION ALL
  7      SELECT
  8          '1.1.1.1.2.2.4.4.4.4.4.5.5.9.11.11.11.15.16.16.19' val
  9      FROM
 10          dual
 11      UNION ALL
 12      SELECT
 13          '1.1.2.2.4.4.4.5.5.9.11.15.16.16.19.19.19' val
 14      FROM
 15          dual
 16  ) SELECT
 17      val,
 18      regexp_replace(val,'([^.]*)([.]\1)+([.]|$)','\1\3') deduplicate 
 19      FROM
 20      tst;
VAL                                                DEDUPLICATE             
------------------------------------------------------------------------
1.1.2.2.4.4.4.5.5.9.11.15.16.16.19                 1.2.4.5.9.11.15.16.19   
1.1.1.1.2.2.4.4.4.4.4.5.5.9.11.11.11.15.16.16.19   1.2.4.5.9.11.15.16.19   
1.1.2.2.4.4.4.5.5.9.11.15.16.16.19.19.19           1.2.4.5.9.11.15.16.19   

Мой подход не обращается к возможным пробелам в строке.Можно просто удалить их отдельно (например, с помощью отдельного оператора замены).

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

К сожалению, Oracle не предоставляет токен для соответствия позиции границы слова.Ни знакомый \b токен, ни древний [[:<:]] или [[:>:]].

Но в этом конкретном наборе вы можете использовать:

(\d+\.)(\1)+

Примечание: вы забыли экранировать точку.

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

Ваше регулярное выражение поймано:

  • a 1 - секунда цифра в 11,
  • , затем точка,
  • и наконец 1 - первая цифра в 15.

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

Наиболееестественным способом написать регулярное выражение, перехватывающее всю последовательность цифр , можно было бы использовать:

  • петлю для начала строки или точки,
  • затем поймать последовательность цифр,
  • и, наконец, поиск точки.

Но так как я не уверен, поддерживает ли Oracle обходные пути, я написал регулярное выражение другим способом:

(^|\.)(\d+)(\.(\2))+

Подробности:

  • (^|\.) - Либо начало строки, либо точка (группа 1) вместо контура.
  • (\d+)- Последовательность цифр (группа 2).
  • ( - Начало группы 3, содержащая:
  • \.(\2) - Точка и та же последовательность цифр, которая попала в группу 2.
  • )+ - Rud группы 3, это может происходить несколько раз.
0 голосов
/ 18 мая 2018

Oracle REGEX не работает так, как вы хотели.Вы можете разбить строку и найти отдельные строки, используя общий метод Разделение строки на несколько строк в Oracle .Другой вариант - использовать XMLTABLE, который работает для чисел, а также строк с правильными кавычками.

SELECT LISTAGG(n, '.') WITHIN
GROUP (
        ORDER BY n
        ) AS n
FROM (
    SELECT DISTINCT TO_NUMBER(column_value) AS n
    FROM XMLTABLE(replace('1.1.2.2.4.4.4.5.5.9.11.15.16.16.19', '.', ','))
    );

Демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...