Switch-Anweisung für den String-Abgleich in JavaScript

193

Wie schreibe ich ein swtich für die folgende Bedingung?

Wenn die URL "foo" enthält , ist settings.base_url "bar".

Mit dem folgenden Effekt wird der erforderliche Effekt erzielt, aber ich habe das Gefühl, dass dies mit einem Switch besser zu handhaben ist:

var doc_location = document.location.href;
var url_strip = new RegExp("http:\/\/.*\/");
var base_url = url_strip.exec(doc_location)
var base_url_string = base_url[0];

//BASE URL CASES

// LOCAL
if (base_url_string.indexOf('xxx.local') > -1) {
    settings = {
        "base_url" : "http://xxx.local/"
    };
}

// DEV
if (base_url_string.indexOf('xxx.dev.yyy.com') > -1) {
    settings = {
        "base_url" : "http://xxx.dev.yyy.com/xxx/"
    };
}
Dr. Frankenstein
quelle

Antworten:

352

Sie können dies nur dann tun, switchwenn Sie einen vollständigen String-Abgleich durchführen. das macht Teilstring- Matching. (Dies ist nicht ganz richtig, wie Sean in den Kommentaren betont. Siehe Anmerkung am Ende.)

Wenn Sie froh sind, dass Ihre Regex an der Spitze alles entfernt, was Sie in Ihrem Match nicht vergleichen möchten, benötigen Sie kein Teilstring-Match und können Folgendes tun:

switch (base_url_string) {
    case "xxx.local":
        // Blah
        break;
    case "xxx.dev.yyy.com":
        // Blah
        break;
}

... aber auch das funktioniert nur, wenn dies die vollständige Zeichenfolge ist, mit der Sie übereinstimmen. Es würde fehlschlagen, wenn beispielsweise base_url_string"yyy.xxx.local" wäre, während Ihr aktueller Code mit dem im Zweig "xxx.local" übereinstimmen würde.


Update : Okay, so technisch Sie können eine Verwendung switchfür Teilzeichenanpassung, aber ich würde es nicht in den meisten Fällen empfehlen. So geht's ( Live-Beispiel ):

function test(str) {
    switch (true) {
      case /xyz/.test(str):
        display("• Matched 'xyz' test");
        break;
      case /test/.test(str):
        display("• Matched 'test' test");
        break;
      case /ing/.test(str):
        display("• Matched 'ing' test");
        break;
      default:
        display("• Didn't match any test");
        break;
    }
}

Dies funktioniert aufgrund der Funktionsweise von JavaScript- switchAnweisungen , insbesondere zweier wichtiger Aspekte: Erstens, dass die Fälle in der Reihenfolge des Quelltextes berücksichtigt werden, und zweitens, dass die Selektorausdrücke (die Bits nach dem Schlüsselwort case) Ausdrücke sind, die als dieser Fall ausgewertet werden ausgewertet (keine Konstanten wie in einigen anderen Sprachen). Da unser Testausdruck lautet true, wird als erster caseAusdruck derjenige trueverwendet, der verwendet wird.

TJ Crowder
quelle
91
Ich weiß, dass es alt ist, aber das ist nicht ganz richtig - Sie können es tatsächlich tunswitch(true) { case /foo/.test(bar): ....
Sean Kinsey
23
Oh Gott nein! Die Switch-Anweisung soll so nicht funktionieren. Das ist einfach kaputt, es sollte illegal sein, solche Sachen zu machen.
Pijusn
47
Hoohoo, so köstlich böse.
Aditya MP
41
Sie alle müssen nur Ihre Perspektive erweitern. Dies ist die Norm in Ruby, außer dass Sie nicht das Hässliche truedort haben, sondern alles zusammen weglassen.
Emkman
49
Ich liebe das und schäme mich nicht, es zuzugeben.
chrisf
65

RegExp kann nicht nur technisch, sondern auch praktisch mit der matchMethode für die Eingabezeichenfolge verwendet werden.

Da die Ausgabe von match()ein Array ist, müssen wir das erste Array-Element des Ergebnisses abrufen. Wenn die Übereinstimmung fehlschlägt, kehrt die Funktion zurücknull . Um einen Ausnahmefehler zu vermeiden, fügen wir den ||bedingten Operator hinzu, bevor wir auf das erste Array-Element zugreifen, und testen die inputEigenschaft , die eine statische Eigenschaft regulärer Ausdrücke ist , die die Eingabezeichenfolge enthält.

str = 'XYZ test';
switch (str) {
  case (str.match(/^xyz/) || {}).input:
    console.log("Matched a string that starts with 'xyz'");
    break;
  case (str.match(/test/) || {}).input:
    console.log("Matched the 'test' substring");        
    break;
  default:
    console.log("Didn't match");
    break;
}

Ein anderer Ansatz besteht darin, den String()Konstruktor zu verwenden, um das resultierende Array zu konvertieren, das nur 1 Element (keine Erfassungsgruppen) enthalten darf, und die gesamte Zeichenfolge muss mit quanitifiers ( .*) in eine Zeichenfolge erfasst werden . Im Falle eines Fehlers wird das nullObjekt zu einer "null"Zeichenfolge. Nicht bequem.

str = 'haystack';
switch (str) {
  case String(str.match(/^hay.*/)):
    console.log("Matched a string that starts with 'hay'");
    break;
}

Eine elegantere Lösung ist die Verwendung des /^find-this-in/.test(str) with- switch (true)Methode, die einfach einen booleschen Wert zurückgibt und die Suche ohne Groß- und Kleinschreibung einfacher macht.

Steven Pribilinskiy
quelle
1
pribilinsiky: Sie sollten wahrscheinlich erwähnen, dass Ihre dritte Lösung (mit test ()) einen Schalter (true) erfordert.
Tag
35

Verwenden Sie einfach die Eigenschaft location.host

switch (location.host) {
    case "xxx.local":
        settings = ...
        break;
    case "xxx.dev.yyy.com":
        settings = ...
        break;
}
Sean Kinsey
quelle
1
Danke, +1, da dies das ist, was ich wirklich tun sollte
Dr. Frankenstein
Sie müssen auf den Variablentyp achten, den Sie an die switch-Anweisung übergeben. Es muss eine Zeichenfolge sein. Um sicher zu sein, dass Sie es tun können switch ("" + location.host).
Ceving
16

Eine andere Option ist die Verwendung des inputFelds eines Regexp-Übereinstimmungsergebnisses :

str = 'XYZ test';
switch (str) {
  case (str.match(/^xyz/) || {}).input:
    console.log("Matched a string that starts with 'xyz'");
    break;
  case (str.match(/test/) || {}).input:
    console.log("Matched the 'test' substring");        
    break;
  default:
    console.log("Didn't match");
    break;
}
Mitar
quelle
Schön. In diesem Fall kann auch jede Array-Eigenschaft zum Testen verwendet werden, z. B..length:
Steven Pribilinskiy
6
var token = 'spo';

switch(token){
    case ( (token.match(/spo/) )? token : undefined ) :
       console.log('MATCHED')    
    break;;
    default:
       console.log('NO MATCH')
    break;;
}


-> Wenn die Übereinstimmung hergestellt ist, gibt der ternäre Ausdruck das ursprüngliche Token zurück
----> Das ursprüngliche Token wird nach Groß- und Kleinschreibung ausgewertet

-> Wenn die Übereinstimmung nicht hergestellt wird, gibt der Ternär undefiniert zurück
----> Case bewertet das Token gegen undefiniert, was Ihr Token hoffentlich nicht ist.

Der ternäre Test kann zum Beispiel in Ihrem Fall alles sein

( !!~ base_url_string.indexOf('xxx.dev.yyy.com') )? xxx.dev.yyy.com : undefined 

===========================================

(token.match(/spo/) )? token : undefined ) 

ist ein ternärer Ausdruck.

Der Test in diesem Fall ist token.match (/ spo /), der die Übereinstimmung der im Token enthaltenen Zeichenfolge mit dem regulären Ausdruck / spo / angibt (in diesem Fall die wörtliche Zeichenfolge spo).

Wenn der Ausdruck und die Zeichenfolge übereinstimmen, ergibt sich true und es wird ein Token zurückgegeben (dies ist die Zeichenfolge, mit der die switch-Anweisung arbeitet).

Offensichtlich Token === Token, damit die switch-Anweisung übereinstimmt und der Fall ausgewertet wird

Es ist einfacher zu verstehen, wenn Sie es in Schichten betrachten und verstehen, dass der Drehtest "VOR" der switch-Anweisung ausgewertet wird, sodass die switch-Anweisung nur die Testergebnisse sieht.

James
quelle
Ihre Antwort ist verwirrend. Können Sie das Beispiel und die Erklärung überprüfen und verbessern?
Falsarella
@falsarella Ich erklärte den Teil, von dem ich mir vorstellte, dass du Probleme beim Verstehen hast. Ich glaube nicht, dass ich ein einfacheres Beispiel machen kann. Wenn Sie weitere Fragen haben oder Ihre Schwierigkeiten genauer beschreiben können, kann ich Ihnen weiterhelfen.
James
Ok, jetzt habe ich es verstanden. Ich war verwirrt, weil es offensichtlich ist, dass token.match(/spo/)das passen würde.
Falsarella
3

Es kann einfacher sein. Versuchen Sie so zu denken:

  • Fangen Sie zuerst eine Zeichenfolge zwischen regulären Zeichen
  • danach "Fall" finden

::

// 'www.dev.yyy.com'
// 'xxx.foo.pl'

var url = "xxx.foo.pl";

switch (url.match(/\..*.\./)[0]){
   case ".dev.yyy." :
          console.log("xxx.dev.yyy.com");break;

   case ".some.":
          console.log("xxx.foo.pl");break;
} //end switch
Geery.S
quelle
Upvoted. Aber beachten Sie:TypeError: url.match(...) is null
1111161171159459134
1

Könnte zu spät sein und alles, aber ich mochte dies für den Fall Aufgabe :)

function extractParameters(args) {
    function getCase(arg, key) {
        return arg.match(new RegExp(`${key}=(.*)`)) || {};
    }

    args.forEach((arg) => {
        console.log("arg: " + arg);
        let match;
        switch (arg) {
            case (match = getCase(arg, "--user")).input:
            case (match = getCase(arg, "-u")).input:
                userName = match[1];
                break;

            case (match = getCase(arg, "--password")).input:
            case (match = getCase(arg, "-p")).input:
                password = match[1];
                break;

            case (match = getCase(arg, "--branch")).input:
            case (match = getCase(arg, "-b")).input:
                branch = match[1];
                break;
        }
    });
};

Sie könnten noch weiter gehen und eine Liste mit Optionen übergeben und den regulären Ausdruck mit | behandeln

TacB0sS
quelle
1
Ich würde auch zur Typensicherheit || {}zu || [-1]oder ähnlich wechseln . Warum wird new RegExpnicht nur Schrägstriche verwendet?
Sergey Krasilnikov
Ich habe mir nicht wirklich die Zeit genommen, es zu verfeinern. In dem Moment, als es funktionierte, fuhr ich einfach fort. Ich schäme mich jetzt.
TacB0sS
Keine Panik, das war nur mein Trottel;) Tatsächlich bin ich mir nicht mal sicher, ob ich Recht habe, ich habe versucht, etwas Neues zu lernen.
Sergey Krasilnikov
Nein ... Sie haben Recht ... Ich hätte definitiv generieren und verschönern können. Ich werde es tun, wenn ich wieder zu diesem Code komme. Ich hoffe, es wird bald genug sein :)
TacB0sS