2014-09-01 3 views
2

Я разрабатываю небольшой проект с Рубином на Rails рамках/PostgreSQL в качестве БД, и мне нужно хранить несколько регулярных выражений в таблицу, как это:Идентифицировать конфликтующие регулярные выражения

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

Каждый шаблон будет начать с одной или несколькими определенными цифрами, и продолжаются «неизвестными» цифрами (от 0 до 255 дополнительных цифр).

Люди добавят новые пары в эту таблицу с помощью графического интерфейса, и я бы хотел избежать пересечения, поэтому для моего примера 3 \ d {3} не следует добавлять, потому что он пересекается с 31 \ d { 2} и 32 \ d {2}.

Можно ли проверить существующие выражения для пересечения перед добавлением нового в таблицу DB?

Кроме того, в GUI пользователи будут видеть эти шаблоны как 1XXX, 2XXX, 31XX. Я не люблю показывать им выражения. Может быть, мне не нужно использовать регулярные выражения? Но мне нужно будет искать наиболее подходящий шаблон по определенному числу, например, запрос с номером 3291 должен вернуть мне «client4», запрос «4» должен вернуть «client5».

Какова наилучшая практика в моем случае?

+0

Сколько «неизвестных» допустимо в шаблоне (макс.)? –

+0

255 в идеальном случае, но может быть опущен не менее 30. –

+0

ОК, с этим мною я бы придерживался вашего текущего метода хранения и перевел '32 \ d {2}' на '32XX' на ввод/вывод. У меня также есть идея для вашего вопроса ... –

ответ

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 ...

+1

Хммм .. ваше решение выглядит очень интересно, но я не понимаю некоторых моментов вывода на SQL Fiddle .. например, почему для ввода 771 \ d {1} 1 \ d {3} шаблон был определен как конфликтный? –

+0

@JC: О, мой плохой. шаблон 'LIKE' должен быть привязан. У меня был ведущий '%', который испортил вечеринку. Должен работать сейчас. –

+0

Большое спасибо, я проверю все в моей среде песочницы, но я думаю, что ваше решение сделает трюк. –

Смежные вопросы