我有一个查询,我想匹配一个特定的子字符串。例如,让我们将所有条目与单词“rice”匹配:

# 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。
本质上,我想要套餐(米饭)-套餐(1/2米饭)。我在这里的攻击角度是使用一个将被否定的环视。
# 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”的字符串。

最佳答案

注意(?!r)ice=iceasi不等于r(?!r)是一个负的前瞻,如果它的模式与当前位置右侧的文本匹配,则匹配失败。
实际上,您需要使用'(?<!1/2 )rice'其中(?<!1/2 )是一个负lookbehind,如果其模式与当前位置左侧的文本匹配,则匹配失败。
PostgreSQL demo

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';

结果:
regex - Postgres/TCL风格正则表达式:使用环顾四周来取消匹配-LMLPHP
要将1作为一个整体匹配,请添加一个\y单词边界,'(?<!\y1/2 )rice'(例如,如果希望返回11/2 Rice 1/2 Githeri)。

关于regex - Postgres/TCL风格正则表达式:使用环顾四周来取消匹配,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54322984/

10-16 16:36