13

Stworzyłem ten regex w normalny RegexPostgresql i ActiveRecord gdzie: Regex dopasowania

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

Pasuje pierwsza trójka

first last 
Last first 
First Last 
First name 

Próbuję uzyskać wszystkie rekordy, w których full_name mecze z regex, który napisałem. Używam PostgreSQL

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

To jest moja próba. Próbowałem też SIMILAR TO i ~ bez powodzenia

Odpowiedz

36

Twój LIKE kwerendy:

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

nie zadziała, ponieważ LIKE nie rozumie regex grupie ((...)) lub naprzemiennie (|), podobnie jak tylko rozumie _ dla pojedynczy znak (jak . w regex) i % dla dowolnej sekwencji zero lub więcej znaków (jak .* w regex).

Jeśli przekażesz ten wzór PODOBNY, wówczas nie znajdziesz żadnego innego z powodu problemów z obudową; jednak:

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

zajmie się problemami z przypadkami i znajdzie te same, co w swoim regex.

Jeśli chcesz użyć wyrażenia regularnego (które prawdopodobnie robisz, ponieważ LIKE jest bardzo ograniczone i uciążliwe i PODOBNE jest, cóż, dziwnym produktem gorączkowych umysłów podkomisji standardów SQL), to zechcesz użyć sprawa niewrażliwe operator dopasowanie i oryginalny regex:

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

to przekłada się na tym kawałku AR:

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

Istnieje subtelna zmiana w moim kodu, który trzeba zwrócić uwagę na: i” m używając pojedynczych cudzysłowów dla moich ciągów Ruby, używasz podwójnie cytaty. Backslashes oznaczają więcej w cudzysłowach niż w cudzysłowach, więc '\s' i "\s" to różne rzeczy. Dorzucę kilka to_sql połączeń i można zobaczyć coś ciekawego:

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

Różnica ta prawdopodobnie nie powoduje żadnych problemów, ale trzeba być bardzo ostrożnym ze swoimi strunami kiedy każdy chce korzystać z tego samego znaku ucieczki. Osobiście używam ciągów z pojedynczym cudzysłowem, chyba że specjalnie potrzebuję dodatkowych funkcji interpunkcji ciągów i podwójnych ciągów.

Niektóre dema: http://sqlfiddle.com/#!15/99a2c/6

+1

Jest to jeden z najlepszych odpowiedzi Dostałem tu, dzięki. Nie potrzebuję znaku '+ ', ponieważ jestem prawie pewien, że wszystkie rekordy mają tylko jedną spację. Powodem, dla którego użyłeś symbolu ': pat' było zdefiniowanie wyrażenia regularnego, ponieważ późniejsza wartość jest poprawna? Również gdybym musiał przekazać wiele wartości do SQL, tworzenie symboli pomogłoby śledzić wartości. – Patrick

+1

Używam ': pat' zamiast'?"aby uczynić go bardziej czytelnym, nie ma to większego znaczenia, gdy jest tylko jeden symbol zastępczy, ale ma to miejsce, gdy jest ich więcej lub trzeba użyć tej samej wartości w kilku miejscach. Nadawanie imionom nazw jest czytelnością i wygrywa IMO. W każdym razie, dziękuję, lubię zdobywać punkty i im więcej się ode mnie nauczysz, tym lepiej :) –

+3

FYI: jeśli używasz MySQL, operator '~ *' nie istnieje. Zamiast tego użyj zamiast niego 'REGEXP'. – jerzy

Powiązane problemy