2009-08-21 2 views
6

Wie kann ich das SQL-Schlüsselwort LIKE in JavaScript emulieren?Emulation von SQL wie in JavaScript

Für diejenigen von Ihnen, die nicht wissen, was LIKE ist, dann ist es eine sehr einfache regex, die die Platzhalter unterstützt nur %, die 0 oder mehr Zeichen entspricht, und _, die genau ein Zeichen übereinstimmt.

Allerdings ist es nicht nur möglich, so etwas wie zu tun:

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

... weil die Musterpunkte enthalten könnte, Sterne und andere spezielle Regex Zeichen.

+0

FYI in Ihrem Beispielcode Sie eine schließende Klammer sind vermisst, bevor " '.exec'" – Kip

+0

@Cba rlow: Zögern Sie nicht, ältere 'edit: .. blah' Markierungen beim Bearbeiten zu entfernen.Ziel für "die beste eigenständige Frage"; Die Editierhistorie ist für alle sichtbar, daher ist es nicht nötig, Kommentare zu hinterlassen. :) – sarnold

+0

@sarnold Gotcha! Danke für die Anleitung! –

Antwort

6

Was Sie haben, wird so lange funktionieren, wie Sie zuerst die Regex-Zeichen in Ihrem Muster umgehen. Im Folgenden finden Sie ein Beispiel aus 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'); 
} 

Sie dann Ihren Code implementieren könnten wie:

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

Angenommen, was Sie bereits haben - 'RegExp.like = Funktion (Text) {Rückgabe neuer RegExp ("^"+ (RegExp.escape (Text) .replace (/%/g,". * "). Ersetzen (/ _/g, ".")) + "$"); } 'könnte ein bisschen mehr für ihn wiederverwendbar sein. – gnarf

+0

Die Regex.escape-Implementierung ist ziemlich übertrieben. Zunächst verhindert 'arguments.callee' Vorkommen einige der Optimierungen in modernen Browsern (und ist in ES5-strict veraltet), so dass es besser ist, wenn möglich zu vermeiden. Zweitens gibt es ein unnötiges Entweichen von Zeichen, wenn sie stattdessen in eine Zeichenklasse platziert werden könnten. Hier ist eine kleinere (und wahrscheinlich schnellere) Version, die wir in Prototype.js verwenden - 'RegExp.escape = function (str) {return str.replace (/ ([. * +?^=!: $ {} () | [\] \/\\])/g, '\\ $ 1'); }; ' – kangax

1

Wenn Sie eine Regex verwenden möchten, können Sie jedes Zeichen der Zeichenfolge in eckige Klammern einschließen. Dann hast du nur ein paar Zeichen, um zu entkommen.

Eine bessere Option könnte jedoch sein, die Zielzeichenfolgen abzuschneiden, sodass die Länge mit Ihrer Suchzeichenfolge übereinstimmt, und auf Gleichheit zu prüfen.

2

Hier ist eine Funktion, das ich verwende, basierend auf PHP's preg_quote function:

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

So Ihre Linie würde jetzt sein:

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

Ich war nach einer Antwort suchen die gleiche Frage und kam mit dieser nach Kip Antwort zu lesen:

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); 
} 

Sie können es dann wie folgt verwenden (beachten Sie, dass es Gross-/Kleinschreibung ignoriert):

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

HINWEIS 29/11/2013: Aktualisiert mit RegExp.test() Leistungsverbesserung gemäß Lucios Kommentar unten.

+0

anstelle von !! this.match (..., sollte nicht this.test verwendet werden? ...? –

+0

hi @ LucioM.Tato, x.test() -Methode ist für RegExp-Instanzen, nicht für String Objekt .. [http://www.w3schools.com/jsref/jsref_regexp_test.asp](http://www.w3schools.com/jsref/jsref_regexp_test.asp) –

+0

Es tut mir leid, ich war nicht klar. Erhalte ein Match-Array (teure Regexp) anstelle von .test (bessere Performance). Sollte sein: Rückgabe von neuem RegExp (...) .test (this), anstatt ein Array oder null durch doppelte Negation in boolean zu konvertieren. http://stackoverflow.com/questions/10940137/regex-test-vs-string-match-to-know-if-a-string-matches-a-regular-ausdruck –

0

In Chris Van Opstals Antwort sollten Sie replaceAll anstelle von replace verwenden, um alle Vorkommen von '%' und '_' zu ersetzen. Verweis auf wie replaceAll zu tun - here

0

Johnny kommen in letzter Zeit hier, aber das funktioniert für mich ich es für meine Spa-Seiten verwenden, um zu vermeiden bestimmte Seiten Ergebnisse nach der Standardseite zeigt:

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; 
} 

Nutzung ist - hier möchte ich nicht auf die Werkzeuge alle Ergebnisse anzuzeigen, Kontakt oder Homepages - Ergebnisse() ist eine Funktion, die ich nicht zeigen, hier:

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