Подтвердить что ты не робот

Postgresql и ActiveRecord где: соответствие регулярному выражению

Я создал это регулярное выражение в обычном Regex

/(first|last)\s(last|first)/i

Он соответствует первым трем

first last
Last first
First Last
First name

Я пытаюсь получить все записи, где full_name совпадает с регулярным выражением, которое я написал. Я использую PostgreSQL

Person.where("full_name ILIKE ?", "%(first|last)%(last|first)%")

Это моя попытка. Я также пробовал SIMILAR TO и ~ без везения

4b9b3361

Ответ 1

Ваш запрос LIKE:

full_name ilike '%(first|last)%(last|first)%'

не будет работать, потому что LIKE не понимает группировку регулярных выражений ((...)) или чередование (|), LIKE понимает только _ для одного символа (например, . в регулярном выражении) и % для любой последовательности из нуля или более символов (например, .* в регулярном выражении).

Если вы передадите этот шаблон аналогичному TO, вы найдете 'first last', но ни один из остальных из-за проблем с случаем; однако это:

lower(full_name) similar to '%(first|last)%(last|first)%'

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

Если вы хотите использовать регулярное выражение (которое вы, вероятно, делаете, потому что LIKE очень ограниченно и громоздко, а ПОДОБНОЕ - это странный продукт лихорадочного ума подкомитета по стандартам SQL), тогда вы захотите использовать не зависящий от регистра оператора и исходное регулярное выражение:

full_name ~* '(first|last)\s+(last|first)'

Это переводит этот бит AR:

Person.where('full_name ~* :pat', :pat => '(first|last)\s+(last|first)')
# or this
Person.where('full_name ~* ?', '(first|last)\s+(last|first)')

В моем коде есть тонкое изменение, которое нужно учитывать: я использую одинарные кавычки для строк Ruby, вы используете двойные кавычки. Обратные косые черты означают больше в двойных кавычках, чем в одиночных кавычках, поэтому '\s' и "\s" - разные вещи. Бросьте пару вызовов to_sql, и вы увидите что-то интересное:

> puts Person.where('full_name ~* :pat', :pat => 'a\s+b').to_sql
SELECT "people".* FROM "people"  WHERE (full_name ~* 'a\s+b')

> puts Person.where('full_name ~* :pat', :pat => "a\s+b").to_sql
SELECT "people".* FROM "people"  WHERE (full_name ~* 'a +b')

Это различие, вероятно, не вызывает у вас никаких проблем, но вам нужно быть очень осторожным с вашими строками, когда каждый хочет использовать один и тот же escape-символ. Лично я использую одинарные кавычки, если я специально не нуждаюсь в дополнительных экранах и функциях интерполяции строк в двойных кавычках.

Некоторые демонстрации: http://sqlfiddle.com/#!15/99a2c/6