Аромат Postgres / TCL Regex: отрицание соответствия, используя обходные пути - PullRequest
0 голосов
/ 23 января 2019

У меня есть запрос, в котором я хотел бы сопоставить определенную подстроку. В качестве примера, давайте сопоставим все записи со словом «рис»:

# select name from menus where name ~* 'rice' order by price limit 3;
         name
----------------------
 Rice Veges
 1/2 Rice 1/2 Githeri
 1/2 Rice 1/2 Chapo
(3 rows)

Более конкретное совпадение также работает. Обратите внимание на добавление 1/2

 select name from menus where name ~* '(1/2) rice' order by price limit 3;
         name
----------------------
 1/2 Rice 1/2 Githeri
 1/2 Rice 1/2 Chapo
 1/2 Rice 1/2 Matoke
(3 rows)

Итак, допустим, я хочу выбрать весь рис, но я не хочу записей с 1/2 в нем.

По сути, я хочу Set (Rice) - Set (1/2 Rice). Мой угол атаки здесь - использовать взгляд, который будет отрицаться.

# select name from menus where name ~* '(?!1/2) rice' order by price limit 3;
         name
----------------------
 1/2 Rice 1/2 Chapo
 1/2 Rice 1/2 Githeri
 1/2 Rice 1/2 Matoke


Как видите, вышеприведенное выражение не работает, так как оно все еще соответствует подстроке 1/2

# select name from menus where name ~* '(?!2)\s*rice' order by price limit 3;
         name
----------------------
 Rice Veges
 1/2 Rice 1/2 Githeri
 1/2 Rice 1/2 Chapo

Упрощение выражения для удаления '1 /', которое может вызывать проблемы из-за неправильно экранированных строк, не дает того, что мы хотим.

Мы можем подтвердить, что поддерживаются отрицательные сведения:

# select name from menus where name ~* '(?!r)ice' order by price limit 3;
      name
-----------------
 Juice Container
 Mango Juice
 Passion Juice

Это соответствует любой строке, которая имеет «ice», но перед ней не стоит «r».

1 Ответ

0 голосов
/ 23 января 2019

Обратите внимание, что (?!r)ice = ice как i не равно r. (?!r) - это отрицательное значение lookahead , которое не соответствует совпадению, если его шаблон немедленно сопоставляет текст с справа от текущей позиции.

Вы на самом деле хотите использовать '(?<!1/2 )rice', где (?<!1/2 ) - это отрицательный взгляд сзади, который не соответствует совпадению, если его шаблон соответствует тексту непосредственно слева от текущей позиции.

Демоверсия PostgreSQL :

CREATE TABLE tb1
    (s character varying)
;

INSERT INTO tb1
    (s)
VALUES
    ('Rice Veges'),
    ('1/2 Rice 1/2 Githeri')
;

SELECT * FROM tb1 WHERE s ~* '(?<!1/2 )rice';

Результат:

enter image description here

Чтобы соответствовать 1 как целому слову, добавьте границу слова \y, '(?<!\y1/2 )rice' (например, если вы хотите, чтобы 11/2 Rice 1/2 Githeri было возвращено).

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