在JavaScript中切换字符串匹配的语句

Dr.*_*ein 179 javascript regex switch-statement

如何为以下条件写一个swtich?

如果网址包含 "foo",则settings.base_url为"bar".

以下是实现所需的效果,但我觉得这在交换机中更易于管理:

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/"
    };
}
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 337

switch除非你正在进行完整的字符串匹配,否则你无法做到这一点; 那是在进行子串匹配. (正如肖恩在评论中指出的那样,这并不完全正确.最后请注意.)

如果你很高兴你的顶级正则表达式剥离了你不想在比赛中比较的所有东西,你不需要子串匹配,并且可以:

switch (base_url_string) {
    case "xxx.local":
        // Blah
        break;
    case "xxx.dev.yyy.com":
        // Blah
        break;
}
Run Code Online (Sandbox Code Playgroud)

...但是,只有当你匹配的是完整的字符串时,才有效.如果base_url_string是"yyy.xxx.local"则会失败,而您当前的代码将匹配"xxx.local"分支中的代码.


更新:好的,从技术上讲,你可以使用switchfor substring匹配,但我不建议在大多数情况下使用它.这是如何(实例):

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为JavaScript switch语句的工作方式,特别是两个关键方面:第一,案例以源文本顺序考虑,第二,选择器表达式(关键字后面的位case)是被评估为该案例的表达式评估(不像其他语言中的常量).因此,由于我们的测试表达式是true,导致的第一个case表达式true将是使用的表达式.

  • 我知道它已经老了,但这不是真的 - 你实际上可以做`switch(true){case /foo/.test(bar):.... (86认同)
  • Hoohoo,好吃的邪恶. (43认同)
  • 我喜欢这个,我并不羞于承认. (37认同)
  • 你们都需要拓宽自己的视野.这是Ruby的常态,除了在那里没有丑陋的`true`之外,你只需将它们全部放在一起. (35认同)
  • 天啊,不!Switch语句不应该像那样工作.这很简单,做那样的事情应该是违法的. (21认同)
  • @ NathanC.Tresch:这不是正则表达式部分,它是一个问题,它使用`switch(true)`然后在`case`语句中进行测试.对我来说,"if/else if"系列会更清晰,更易于维护. (7认同)
  • 我非常喜欢你的最新解决方案.我认为这通常产生比if/else语句列表更可读的代码,并且没有比该构造更多的开销.我正在使用它在express.js应用程序上进行用户代理检测. (6认同)
  • 有趣的是,Mozilla在他们的[MDN docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch#Method_Two)中包含一个`switch(true)`示例声明.他们实际上称之为"hacky". (3认同)
  • @RexSchrader:你知道,我越看越好,我觉得它更适合某些情况...... :-) (3认同)
  • @Sean:呃.是的,你是对的(潜伏者:[例子](http://jsbin.com/ehabar)),但不要去那里...... ;-) (2认同)
  • @CurtisRutland:大声笑!您必须记住,MDN是协作的(就像SO),由社区编辑... :-) (2认同)

Ste*_*kiy 53

RegExp可以在输入字符串上使用,不仅在技术上,而且实际上也与match方法一起使用.

因为输出match()是一个数组,我们需要检索结果的第一个数组元素.当匹配失败时,函数返回null.为了避免异常错误,我们将||在访问第一个数组元素之前添加条件运算符,并针对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;
}
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用String()构造函数转换必须只有1个元素(没有捕获组)的结果数组,并且必须使用quanitifiers(.*)将整个字符串捕获到字符串.如果失败,null对象将变为"null"字符串.不方便.

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

无论如何,更优雅的解决方案是使用/^find-this-in/.test(str)with switch (true)方法,它只返回一个布尔值,并且在没有区分大小写的情况下更容易搜索.

  • pribilinsiky:你可能应该提到你的第三个解决方案(使用 test())要求你有 switch(true)。 (2认同)

Sea*_*sey 35

只需使用location.host属性即可

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

  • 谢谢,+1,因为这才是我真正应该做的 (2认同)

Mit*_*tar 13

另一种选择是使用正则表达式匹配结果的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;
}
Run Code Online (Sandbox Code Playgroud)


Mag*_*ero 5

var token = 'spo';

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


->如果匹配,则三元表达式返回原始标记
---->原始标记按大小写求值

->如果未进行匹配,则三进制返回undefined
----> Case将根据undefined评估令牌,希望您的令牌不是。

三元测试可以是任何情况,例如您的情况

( !!~ base_url_string.indexOf('xxx.dev.yyy.com') )? xxx.dev.yyy.com : undefined 
Run Code Online (Sandbox Code Playgroud)

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

(token.match(/spo/) )? token : undefined ) 
Run Code Online (Sandbox Code Playgroud)

三元表达式。

这种情况下的测试是token.match(/ spo /),它声明令牌中包含的字符串与正则表达式/ spo /的匹配(在这种情况下为文字字符串spo)。

如果表达式和字符串匹配,则结果为true并返回令牌(这是switch语句在其上操作的字符串)。

显然,记号===记号,因此switch语句被匹配并评估了大小写

如果您逐层查看它并了解Turnery测试是在switch语句“之前”进行评估的,则更容易理解,以便switch语句仅看到测试结果。