13

Ho creato questo regex nel normale RegexPostgreSQL e ActiveRecord dove: Regex corrispondenza

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

Si abbina i primi tre dei

first last 
Last first 
First Last 
First name 

Sto cercando di ottenere tutti i record in cui il full_name incontri la regex che ho scritto. Sto usando PostgreSQL

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

Questo è il mio tentativo. Ho anche provato SIMILAR TO e ~ senza fortuna

risposta

36

Vostri criteri LIKE:

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

non funzionerà perché LIKE non capisce raggruppamento regex ((...)) o alternanza (|), COME capisce solo _ per un singolo carattere (come . in un'espressione regolare) e % per qualsiasi sequenza di zero o più caratteri (come .* in un'espressione regolare).

Se si passa questo modello a SIMILE A, allora si troverà 'first last' ma nessuno degli altri a causa di problemi di caso; tuttavia, questo:

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

si prenderà cura dei problemi del caso e troverà gli stessi del tuo regex.

Se si desidera utilizzare un'espressione regolare (cosa che probabilmente si fa perché LIKE è molto limitato, ingombrante e SIMILE è, beh, uno strano prodotto delle menti febbrili di qualche sottocomitato SQL standard), allora si vorrà usare l'operatore di corrispondenza case-insensitive e la tua regex originale:

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

che si traduce in questo po 'di AR:

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

C'è un sottile cambiamento nel mio codice che è necessario prendere nota di: I' m usando le virgolette singole per le mie stringhe di Ruby, stai usando il doppio citazioni. Le barre rovesciate significano più stringhe con doppia quotatura rispetto a stringhe con quotatura singola, pertanto '\s' e "\s" sono cose diverse. Toss in un paio di to_sql chiamate e si potrebbe vedere qualcosa di interessante:

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

Questa differenza probabilmente non è causando problemi, ma è necessario essere molto attenti con le corde, quando tutti vogliono utilizzare lo stesso carattere di escape. Personalmente, io uso solo le stringhe tra virgolette, a meno che io non abbia bisogno in particolare delle funzioni di escape e interpolazione delle stringhe tra doppie stringhe tra virgolette.

Alcune demo: http://sqlfiddle.com/#!15/99a2c/6

+1

Questa è una delle migliori risposte che ho ricevuto qui, grazie. Non ho bisogno del '+' perché sono abbastanza sicuro che tutti i record abbiano solo uno spazio. Il motivo per cui è stato utilizzato il simbolo ': pat' era definire la regex come il valore più tardi corretto? Inoltre, se avessi bisogno di passare più valori in SQL, la creazione di simboli aiuterebbe a tenere traccia dei valori. – Patrick

+1

Io uso ': pat' invece di'?'Per renderlo un po 'più leggibile, non importa molto quando c'è un solo segnaposto ma lo fa quando ce ne sono altri o se è necessario utilizzare lo stesso valore in più punti. Dare nomi alle cose è una leggibilità vincere IMO. Comunque, grazie, mi piace guadagnare i miei punti e più impari da me il meglio :) –

+3

FYI: se usi MySQL, l'operatore '~ *' non esiste. Invece, usa "REGEXP" al suo posto. – jerzy