Istruzione switch per la corrispondenza delle stringhe in JavaScript


193

Come faccio a scrivere uno swtich per il seguente condizionale?

Se l'URL contiene "pippo", allora settings.base_url è "bar".

Quanto segue sta ottenendo l'effetto richiesto ma ho la sensazione che sarebbe più gestibile in un interruttore:

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

Risposte:


352

Non puoi farlo in a a switchmeno che tu non stia eseguendo la corrispondenza della stringa completa ; che sta facendo la corrispondenza della sottostringa . (Questo non è del tutto vero, come sottolinea Sean nei commenti. Vedi nota alla fine.)

Se sei felice che la tua regex in alto stia togliendo tutto ciò che non vuoi confrontare nella tua partita, non hai bisogno di una corrispondenza di sottostringa e potresti fare:

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

... ma di nuovo, funziona solo se questa è la stringa completa che stai abbinando. Non riuscirebbe se base_url_string, ad esempio, "yyy.xxx.local", mentre il codice corrente corrispondesse a quello nel ramo "xxx.local".


Aggiornamento : Ok, quindi tecnicamente puoi usare un switchper la corrispondenza della sottostringa, ma non lo consiglierei nella maggior parte delle situazioni. Ecco come ( esempio live ):

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

Funziona a causa del modo in switchcui funzionano le istruzioni JavaScript , in particolare due aspetti chiave: in primo luogo, che i casi sono considerati nell'ordine del testo di origine , e in secondo luogo che le espressioni del selettore (i bit dopo la parola chiave case) sono espressioni che vengono valutate come tale valutato (non costanti come in alcune altre lingue). Quindi, poiché la nostra espressione di test è true, la prima caseespressione che ne risulta truesarà quella che viene utilizzata.


91
So che è vecchio, ma questo non è del tutto vero - puoi davvero farloswitch(true) { case /foo/.test(bar): ....
Sean Kinsey il

23
Oh dio, no! L'istruzione switch non dovrebbe funzionare in questo modo. Questo è semplicemente rotto, dovrebbe essere illegale fare cose del genere.
Pijusn,

47
Hoohoo, deliziosamente malvagio.
Aditya MP

41
Devi solo ampliare la tua prospettiva. Questa è la norma in Ruby, tranne che invece di avere il brutto truelì, lo lasci fuori tutti insieme.
Emkman,

49
Adoro questo e non mi vergogno di ammetterlo.
chrisf,

65

RegExp può essere utilizzato sulla stringa di input non solo tecnicamente ma anche con il matchmetodo.

Poiché l'output di match()è un array, è necessario recuperare il primo elemento array del risultato. Quando la partita fallisce, la funzione ritorna null. Per evitare un errore di eccezione, aggiungeremo l' ||operatore condizionale prima di accedere al primo elemento dell'array e testeremo la inputproprietà che è una proprietà statica delle espressioni regolari che contiene la stringa di input.

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

Un altro approccio consiste nell'utilizzare il String()costruttore per convertire l'array risultante che deve avere solo 1 elemento (nessun gruppo di acquisizione) e l'intera stringa deve essere acquisita con quanitifiers ( .*) in una stringa. In caso di guasto l' nulloggetto diventerà una "null"stringa. Non conveniente.

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

Ad ogni modo, una soluzione più elegante è quella di utilizzare il metodo /^find-this-in/.test(str)with switch (true)che restituisce semplicemente un valore booleano ed è più facile cercare senza maiuscole e minuscole.


1
pribilinsiky: dovresti probabilmente menzionare che la tua terza soluzione (usando test ()) richiede di avere switch (true).
trad

35

Basta usare la proprietà location.host

switch (location.host) {
    case "xxx.local":
        settings = ...
        break;
    case "xxx.dev.yyy.com":
        settings = ...
        break;
}

1
Grazie, +1 poiché è quello che dovrei fare davvero
dottor Frankenstein,

Devi fare attenzione al tipo di variabile che passi all'istruzione switch. Essa deve essere una stringa. Per essere sicuri di poterlo fare switch ("" + location.host).
ceving l'

16

Un'altra opzione è quella di utilizzare il inputcampo del risultato di una partita regexp :

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

Ben fatto. In questo caso è possibile utilizzare anche qualsiasi proprietà dell'array per il test, ad es..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;;
}


-> Se viene effettuata la corrispondenza, l'espressione ternaria restituisce il token originale
----> Il token originale viene valutato per caso

-> Se la partita non viene stabilita, il ternario ritorna indefinito
----> Caso valuta il token rispetto a undefined, che si spera non sia.

Il test ternario può essere qualsiasi cosa, ad esempio nel tuo caso

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

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

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

è un'espressione ternaria.

Il test in questo caso è token.match (/ spo /) che indica la corrispondenza della stringa mantenuta in token rispetto all'espressione regex / spo / (che in questo caso è la stringa letterale spo).

Se l'espressione e la stringa corrispondono, si traduce in vero e restituisce token (che è la stringa su cui opera l'istruzione switch).

Ovviamente token === token in modo che l'istruzione switch sia abbinata e il caso valutato

È più facile capire se lo si guarda a strati e si capisce che il test di torneria viene valutato "PRIMA" dell'istruzione switch in modo che l'istruzione switch veda solo i risultati del test.


La tua risposta è confusa. Puoi rivedere e migliorare l'esempio e la spiegazione?
falsarella,

@falsarella Ho spiegato la parte che immaginavo tu abbia avuto difficoltà a capire. Non credo di poter fare un esempio più semplice. Se hai più domande o puoi essere più specifico con le tue difficoltà, posso aiutarti di più.
James,

Ok, ora ho capito. Ero confuso perché è ovvio che token.match(/spo/)corrisponderebbe.
falsarella,

3

Potrebbe essere più semplice Prova a pensare in questo modo:

  • per prima cosa prendi una stringa tra caratteri normali
  • dopo che trovare "caso"

:

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

Upvoted. Ma nota:TypeError: url.match(...) is null
1111161171159459134

1

Potrebbe essere troppo tardi e tutto, ma mi è piaciuto questo nel caso di assegnazione :)

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

potresti andare oltre e passare un elenco di opzioni e gestire la regex con |


1
Vorrei anche cambiare || {}per || [-1]o simili per la sicurezza tipo. Inoltre, perché viene new RegExputilizzato, non solo le barre?
Sergey Krasilnikov,

non ho davvero avuto il tempo di perfezionarlo .. nel momento in cui ha funzionato ho solo continuato ..... mi vergogno ora.
TacB0sS,

Non fatevi prendere dal panico, era solo il mio pignolo;) In realtà non sono nemmeno sicuro di aver ragione, ho cercato di imparare qualcosa di nuovo.
Sergey Krasilnikov,

No ... hai ragione ... Avrei sicuramente potuto generarlo e prettificarlo .. Lo farò quando tornerò a quel codice .. sarà abbastanza presto spero :)
TacB0sS,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.