Question PostgreSQL et ActiveRecord où: Regex correspondant


J'ai créé cette regex dans Regex normale

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

Il correspond aux trois premiers

first last
Last first
First Last
First name

J'essaie d'obtenir tous les dossiers où le full_name correspond au regex que j'ai écrit. J'utilise PostgreSQL

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

C'est ma tentative. J'ai aussi essayé SIMILAR TO et ~ sans chance


14
2018-04-02 00:56


origine


Réponses:


Votre requête LIKE:

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

ne fonctionnera pas parce que COMME ne comprend pas le regroupement d'expressions rationnelles ((...)) ou alternance (|), LIKE ne comprend que _ pour un seul personnage (comme . dans une regex) et % pour toute séquence de zéro ou plusieurs caractères (comme .* dans une regex).

Si vous remettez ce modèle à SIMILAR TO, vous trouverez 'first last' mais aucun des autres en raison de problèmes de cas; cependant, ceci:

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

s'occupera des problèmes de cas et trouvera les mêmes que votre regex.

Si vous voulez utiliser une regex (ce que vous faites probablement parce que LIKE est très limité et encombrant et que SIMILAR TO est, eh bien, un produit étrange des sous-comités de normes SQL), alors vous voudrez utiliser la casse opérateur correspondant et votre expression originale:

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

Cela se traduit par ce bit d'AR:

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

Il y a un changement subtil dans mon code que vous devez prendre en compte: j'utilise des guillemets simples pour mes chaînes Ruby, vous utilisez des guillemets doubles. Les barres obliques inverses signifient plus de chaînes doubles que de simples chaînes entre guillemets '\s' et "\s" sont des choses différentes Mélanger dans un couple to_sql appels et vous pourriez voir quelque chose d'intéressant:

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

Cette différence ne vous pose probablement aucun problème, mais vous devez faire très attention à vos chaînes lorsque tout le monde veut utiliser le même caractère d'échappement. Personnellement, j'utilise des chaînes entre guillemets simples sauf si j'ai spécifiquement besoin des fonctions supplémentaires d'échappement et d'interpolation de chaîne des chaînes entre guillemets.

Quelques démos: http://sqlfiddle.com/#!15/99a2c/6


38
2018-04-02 03:15