识别冲突的正则表达式

时间:2014-09-01 18:58:31

标签: sql ruby-on-rails ruby regex postgresql

我正在开发一个使用Ruby on Rails框架/ PostgreSQL作为DB的小项目,我需要在表中存储一些正则表达式,如下所示:

------------------------
pattern       direction
-----------------------
1\d{3}        client1        
2\d{3}        client2
31\d{2}       client3
32\d{2}       client4
4             client5
-----------------------

每个模式都会以一个或多个某些数字开头,然后由未知的"数字(从0到255个附加数字)。

人们会通过GUI为这个表添加新的对,我想避免交叉,所以对于我的例子3 \ d {3}不应该被允许添加,因为它确实与31 \ d交叉{2}和32 \ d {2}。

在将新的表达式添加到数据库表之前,是否可以检查交集的现有表达式?

此外,在GUI中,用户将看到这些模式,如1XXX,2XXX,31XX。我不想向他们展示表达方式。也许我根本不必使用正则表达式?但我需要按一定的数字搜索最佳匹配模式,例如,使用数字3291的查询应该返回我" client4",query" 4"应该返回" client5"。

在我的案例中,最佳做法是什么?

1 个答案:

答案 0 :(得分:2)

基本上,在以下情况下禁止新条目:

  • 总长度匹配。
  • 前缀是条目的子字符串,反之亦然。

您可以冗余地存储总长度或动态计算。我根据问题中显示的模式将公式封装在一个简单的SQL函数中:

CREATE OR REPLACE FUNCTION f_pattern_len(text)
  RETURNS int AS
$$
SELECT COALESCE(substring($1, '(\d*)}$')::int, 0) -- digits in prefix
       + length(substring($1, '^\d*'))            -- digits in pattern
$$ LANGUAGE SQL IMMUTABLE STRICT;

然后,在INSERT上,请按以下方式检查:

INSERT INTO tbl (pattern, direction)
SELECT i.input, 'client66'::text
FROM  (SELECT '3\d{7}'::text AS input) i
LEFT   JOIN tbl t
    ON f_pattern_len(t.pattern) = f_pattern_len(i.input)
   AND (substring(t.pattern, '^\d*') LIKE (substring(i.input, '^\d*') || '%') OR
        substring(i.input, '^\d*') LIKE (substring(t.pattern, '^\d*') || '%'))
WHERE t.pattern IS NULL

SQL Fiddle.

您也可以将逻辑放入触发器BEFORE INSERT ...