Cambiar la instrucción para la coincidencia de cadenas en JavaScript

193

¿Cómo escribo un swtich para el siguiente condicional?

Si la url contiene "foo", entonces settings.base_url es "bar".

Lo siguiente es lograr el efecto requerido, pero tengo la sensación de que esto sería más manejable en un cambio:

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
fuente

Respuestas:

352

No puede hacerlo de una manera a switchmenos que esté haciendo una coincidencia de cadena completa ; eso está haciendo coincidencia de subcadenas . (Esto no es del todo cierto, como señala Sean en los comentarios. Ver nota al final).

Si está contento de que su expresión regular en la parte superior esté eliminando todo lo que no desea comparar en su coincidencia, no necesita una coincidencia de subcadena y podría hacer:

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

... pero de nuevo, eso solo funciona si esa es la cadena completa con la que coinciden. base_url_stringFallaría si fuera, por ejemplo, "aaa.xxx.local", mientras que su código actual coincidiría con el de la rama "xxx.local".


Actualización : Bueno, por lo que técnicamente se puede utilizar una switchde subcadena coincidente, pero yo no lo recomendaría en la mayoría de las situaciones. Así es como ( ejemplo en vivo ):

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

Eso funciona debido a la forma en switchque funcionan las declaraciones de JavaScript , en particular dos aspectos clave: Primero, que los casos se consideran en orden de texto de origen , y segundo, que las expresiones del selector (los bits después de la palabra clave case) son expresiones que se evalúan como ese caso es evaluado (no constantes como en algunos otros idiomas). Entonces, dado que nuestra expresión de prueba es true, la primera caseexpresión que resulte trueserá la que se use.

TJ Crowder
fuente
9191
Sé que es viejo, pero esto no es del todo cierto, en realidad puedes hacerloswitch(true) { case /foo/.test(bar): ....
Sean Kinsey
23
¡Oh, Dios, no! No se supone que la declaración de cambio funcione de esa manera. Esto simplemente se rompe, debería ser ilegal hacer cosas así.
Pijusn
47
Hoohoo, tan deliciosamente malvado.
Aditya MP
41
Todos ustedes solo necesitan ampliar su perspectiva. Esta es la norma en Ruby, excepto que en lugar de tener lo feo trueallí, simplemente lo dejas todo junto.
emkman
49
Me encanta esto y no me da vergüenza admitirlo.
chrisf
65

RegExp se puede usar en la cadena de entrada no solo técnicamente sino prácticamente con match método.

Debido a que la salida de la match()es una matriz, necesitamos recuperar el primer elemento de la matriz del resultado. Cuando la coincidencia falla, la función regresa null. Para evitar un error de excepción, agregaremos el ||operador condicional antes de acceder al primer elemento de matriz y probaremos con la inputpropiedad que es una propiedad estática de expresiones regulares que contiene la cadena de entrada.

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

Otro enfoque es usar el String()constructor para convertir la matriz resultante que debe tener solo 1 elemento (sin grupos de captura) y la cadena completa debe capturarse con quanitifiers ( .*) en una cadena. En caso de falla, el nullobjeto se convertirá en una "null"cadena. No conveniente.

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

De todos modos, una solución más elegante es usar el /^find-this-in/.test(str)conswitch (true) método que simplemente devuelve un valor booleano y es más fácil de buscar sin distinción entre mayúsculas y minúsculas.

Steven Pribilinskiy
fuente
1
pribilinsiky: probablemente debería mencionar que su tercera solución (usando test ()) requiere que tenga un interruptor (verdadero).
día de
35

Solo usa la propiedad location.host

switch (location.host) {
    case "xxx.local":
        settings = ...
        break;
    case "xxx.dev.yyy.com":
        settings = ...
        break;
}
Sean Kinsey
fuente
1
Gracias, +1 ya que esto es lo que debería estar haciendo realmente
Dr. Frankenstein
Debe tener cuidado con el tipo de variable que pasa a la instrucción de cambio. Se debe ser una cadena. Para estar seguro de que puedes hacer switch ("" + location.host).
ceving
16

Otra opción es utilizar el inputcampo de un resultado de coincidencia 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;
}
Mitar
fuente
Buena esa. En este caso, cualquier propiedad de matriz también se puede utilizar para la prueba, por ejemplo.length:
Steven Pribilinskiy, el
6
var token = 'spo';

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


-> Si se hace la coincidencia, la expresión ternaria devuelve el token original
----> El token original se evalúa por caso

-> Si la coincidencia no se realiza, el ternario devuelve indefinido
----> El caso evalúa el token contra indefinido, lo que esperamos que no sea tu token.

La prueba ternaria puede ser cualquier cosa, por ejemplo, en su caso

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

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

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

es un expresión ternaria.

La prueba en este caso es token.match (/ spo /) que establece la coincidencia de la cadena contenida en el token con la expresión regular / spo / (que es la cadena literal spo en este caso).

Si la expresión y la cadena coinciden, da como resultado verdadero y devuelve el token (que es la cadena en la que opera la instrucción switch).

Obviamente token === token para que la declaración de cambio coincida y se evalúe el caso

Es más fácil de entender si lo mira en capas y comprende que la prueba de tornería se evalúa "ANTES" de la declaración de cambio para que la declaración de cambio solo vea los resultados de la prueba.

James
fuente
Tu respuesta es confusa. ¿Puedes revisar y mejorar el ejemplo y la explicación?
falsarella
@falsarella Le expliqué la parte que imaginé que tenía problemas para entender. No creo que pueda dar un ejemplo más simple. Si tiene más preguntas o puede ser más específico con sus dificultades, puedo ayudarlo más.
James
Ok, ahora lo tengo. Estaba confundido porque es obvio que token.match(/spo/)coincidiría.
falsarella
3

Puede ser mas facil. Intenta pensar así:

  • primero atrape una cadena entre caracteres regulares
  • después de eso encontrar "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
Geery.S
fuente
Votado Pero tenga en cuenta:TypeError: url.match(...) is null
1111161171159459134
1

Podría ser demasiado tarde y todo, pero me gustó esto en caso de asignación :)

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

podría llevarlo más allá, pasar una lista de opciones y manejar la expresión regular con |

TacB0sS
fuente
1
También cambiaría || {}a || [-1]o similar por tipo de seguridad. Además, ¿por qué se new RegExpusa, no solo barras?
Sergey Krasilnikov
en realidad no me tomé el tiempo para refinarlo ... en el momento en que funcionó, simplemente continué ... Me siento avergonzado ahora.
TacB0sS
No entre en pánico, eso fue solo mi picardía;) De hecho, ni siquiera estoy seguro de tener razón, traté de aprender algo nuevo.
Sergey Krasilnikov
No ... tienes razón ... Definitivamente podría haber generado y prettificado ... Lo haré cuando llegue a ese código nuevamente ... será lo suficientemente pronto, espero :)
TacB0sS