2009-08-21 19 views
6

Jak mogę emulować słowo kluczowe SQL LIKE w JavaScript?Emulacja SQL LIKE w JavaScript

Dla tych z Was, którzy nie wiedzą, co LIKE jest to bardzo proste wyrażenie regularne, które obsługuje tylko symbole wieloznaczne %, który pasuje do 0 lub więcej znaków, a _ który odpowiada dokładnie jeden znak.

Jednak to nie tylko możliwe, aby zrobić coś takiego:

var match = new RegEx(likeExpr.replace("%", ".*").replace("_", ".")).exec(str) != null; 

... ponieważ wzór może zawierać kropki, gwiazdki i inne znaki specjalne regex.

+0

fyi- w kodzie próbki tracisz bliską przed nawias " '.exec'" – Kip

+0

@ C.ba rlow: nie wahaj się usuwać starsze oznaczenia "edit: .. blah" podczas edycji.Cel "najlepszego samodzielnego pytania"; Historia edycji jest dostępna dla wszystkich, więc nie trzeba komentować. :) – sarnold

+0

@sarnold Gotcha! Dzięki za wskazówki! –

Odpowiedz

6

To, co masz, będzie działać tak długo, jak będziesz pierwszy raz uciec przed znakami wyrażeń regularnych we wzorcu. Poniżej znajduje się przykład z Simon Willison’s blog:

RegExp.escape = function(text) { 
    if (!arguments.callee.sRE) { 
    var specials = [ 
     '/', '.', '*', '+', '?', '|', 
     '(', ')', '[', ']', '{', '}', '\\' 
    ]; 
    arguments.callee.sRE = new RegExp(
     '(\\' + specials.join('|\\') + ')', 'g' 
    ); 
    } 
    return text.replace(arguments.callee.sRE, '\\$1'); 
} 

Następnie można wdrożyć swój kod jako:

likeExpr = RegExp.escape(likeExpr); 
var match = new RegEx(likeExpr.replace("%", ".*").replace("_", ".")).exec(str) != null; 
+1

Zakładając, co już masz - "RegExp.like = funkcja (tekst) {return new RegExp ("^"+ (RegExp.escape (tekst) .replace (/%/g,". * "). Replace (/ _/g, ".")) + "$"); } 'może być dla niego trochę więcej do ponownego użytku. – gnarf

+0

To wdrożenie 'Regex.escape' jest całkiem przesadą. Przede wszystkim wystąpienie 'arguments.callee' zapobiega niektórym optymalizacjom w nowoczesnych przeglądarkach (i jest nieaktualne w wersji ES5-strict), więc lepiej jest go unikać, gdy jest to możliwe. Po drugie, niepotrzebne jest ucieczkę postaci, gdy zamiast tego można je umieścić w klasie postaci. Oto mniejsza (i najprawdopodobniej szybsza) wersja, której używamy w Prototype.js - 'RegExp.escape = function (str) {return str.replace (/ ([. * +?^=!: $ {} () | [\] \/\\])/g, '\\ $ 1'); }; ' – kangax

1

Jeśli chcesz użyć wyrażenia regularnego, możesz zawinąć każdy znak ciągu w nawiasy kwadratowe. Wtedy masz tylko kilka postaci do ucieczki.

Ale lepszym rozwiązaniem może być obcięcie pasm docelowych, aby długość pasowała do wyszukiwanego ciągu i sprawdzanie równości.

2

Oto funkcja używam, na podstawie PHP's preg_quote function:

function regex_quote(str) { 
    return str.replace(new RegExp("([\\.\\\\\\+\\*\\?\\[\\^\\]\\$\\(\\)\\{\\}\\=\\!\\<\\>\\|\\:\\-])", "g"), "\\$1"); 
} 

Więc linia będzie teraz będzie:

var match = new RegEx(regex_quote(likeExpr).replace("%", ".*").replace("_", ".")).exec(str) != null; 
3

szukałem odpowiedzi na to samo pytanie i wymyślił ten po przeczytaniu Kip za odpowiedź:

String.prototype.like = function(search) { 
    if (typeof search !== 'string' || this === null) {return false; } 
    // Remove special chars 
    search = search.replace(new RegExp("([\\.\\\\\\+\\*\\?\\[\\^\\]\\$\\(\\)\\{\\}\\=\\!\\<\\>\\|\\:\\-])", "g"), "\\$1"); 
    // Replace % and _ with equivalent regex 
    search = search.replace(/%/g, '.*').replace(/_/g, '.'); 
    // Check matches 
    return RegExp('^' + search + '$', 'gi').test(this); 
} 

można następnie wykorzystać je w następujący sposób (zauważ, że ignoruje dużymi/małymi literami):

var url = 'http://www.mydomain.com/page1.aspx'; 
console.log(url.like('%mydomain.com/page_.asp%')); // true 

UWAGA 29/11/2013: Zaktualizowane o RegExp.test() poprawę wydajności zgodnie z komentarzem Lucios poniżej.

+0

zamiast !! this.match (..., nie powinieneś używać this.test (...? –

+0

hi @ LucioM.Tato, x.test() metoda jest dla instancji RegExp, a nie dla String obiekt .. [http://www.w3schools.com/jsref/jsref_regexp_test.asp](http://www.w3schools.com/jsref/jsref_regexp_test.asp) –

+0

Przykro mi, nie byłam jasna. ponownie uzyskujesz tablicę dopasowań (kosztowne wyrażenie regularne) zamiast używać .test (lepsza wydajność) Powinno być: zwrócenie nowego RegExp (...) .test (this), zamiast konwertować tablicę lub null na boolean przez podwójne negowanie. http://stackoverflow.com/questions/10940137/regex-test-vs-string-match-to-know-if-a-string-matches-a-regular-expression –

0

W odpowiedzi Chrisa Van Opstala należy użyć replaceAll zamiast zastąpić, aby zastąpić wszystkie wystąpienia "%" i "_". odniesienia do tego, jak to zrobić replaceAll - here

0

Johnny przyjść ostatnio tutaj, ale to działa na mnie użyć go do moich stron spa, aby uniknąć pewnych stron przedstawiający wyniki po domyślnej strony:

function like(haystack,needle){ 
    needle = needle.split(','); 
    var str = haystack.toLowerCase(); 
    var n = -1; 
    for(var i=0;i<needle.length;i++){ 
     n = str.search(needle[i]); 
     if(n > -1){ 
      return n; 
     } 
    } 
return n; 
} 

użycie jest - Chcę tu nie wykazują żadnych wyników na narzędziach, kontaktowych lub domowych stron - wyniki() jest funkcją nie pokazuję tutaj:

var n = like($data,'tools,contact,home'); 
//~ alert(n); 
if(n < 0){// does not match anything in the above string 
    results($data); 
}