Переключити оператор для відповідності рядків у JavaScript


193

Як мені написати swtich для наступного умовного?

Якщо URL містить "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/"
    };
}

Відповіді:


352

Ви не можете це зробити, switchякщо не виконаєте повне узгодження рядків; це робить відповідність підрядків . (Це не зовсім вірно, як в коментарях вказує Шон. Дивіться примітку в кінці.)

Якщо ви щасливі, що ваш регекс вгорі знімає все, що ви не хочете порівнювати у вашому матчі, вам не потрібна відповідна підрядка, і ви можете:

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

... але знову ж таки, це працює лише в тому випадку, якщо це повна відповідна рядок. Не вдасться, якби base_url_string, скажімо, "yyy.xxx.local", тоді як ваш поточний код відповідатиме цьому у гілці "xxx.local".


Оновлення : Гаразд, тому технічно ви можете використовувати switchдля відповідності підрядків, але я б не рекомендував це в більшості ситуацій. Ось як ( живий приклад ):

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

Це працює через те, як switchпрацюють оператори JavaScript , зокрема два ключові аспекти: По-перше, випадки розглядаються у порядку вихідного тексту , а по-друге, що вирази селектора (біти після ключового слова case) є виразами , які оцінюються як такий випадок. оцінюється (не константи, як у деяких інших мовах). Отже, оскільки наш тестовий вираз є trueпершим case, trueдо якого виходить, буде те, що звикає.


91
Я знаю, що це старе, але це не зовсім правда - ви насправді можете це зробитиswitch(true) { case /foo/.test(bar): ....
— Шон Кінсі

23
О боже, ні! Оператор Switch не повинен працювати так. Це просто порушено, робити подібні речі потрібно незаконно.
— Піжусн

47
Хуху, так смачно злий.
— Адітя МП

41
Вам усім просто потрібно розширити свою точку зору. Це норма в Рубі, окрім того, що замість того, щоб trueтам було негарне , ви просто залишаєте це все разом.
— emkman

49
Я люблю це і мені не соромно це визнати.
— chrisf

65

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

Інший підхід полягає у використанні String()конструктора для перетворення отриманого масиву, який повинен містити лише 1 елемент (без груп захоплення), а ціла рядок повинна бути захоплена кількісними показниками ( .*) у рядок. У разі відмови nullоб'єкт стане "null"рядком. Не зручно.

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

У будь-якому випадку, більш елегантним рішенням є використання методу /^find-this-in/.test(str)with, switch (true)який просто повертає булеве значення і його простіше шукати без чутливості до регістру.


1
pribilinsiky: напевно, ви повинні згадати, що для вашого третього рішення (за допомогою тесту ()) вам потрібно мати перемикач (вірно).
— торг

35

Просто використовуйте властивість location.host

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

1
Дякую, +1, оскільки це я повинен робити насправді
— доктор Франкенштейн,

Ви повинні подбати про тип змінної, який ви передаєте в оператор переключення. Це має бути рядок. Щоб бути впевненим, ви можете зробити switch ("" + location.host).
— закінчення

16

Іншим варіантом є використання 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;
}

хороший. У цьому випадку будь-яке властивість масиву також може бути використане для перевірки, наприклад.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;;
}


-> Якщо збіг зроблений, потрійний вираз повертає початковий маркер
----> Оригінальний маркер оцінюється на випадок

-> Якщо відповідність не виконана, тернар повертається невизначеним
----> Case оцінює маркер проти невизначеного, що, сподіваємось, ваш маркер не є.

Тест потрійним може бути будь-яким, наприклад, у вашому випадку

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

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

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

є потрійним виразом.

Тест у цьому випадку - token.match (/ spo /), який констатує відповідність рядка, що міститься в токені, проти виразу регулярного виразу / spo / (що є буквальним рядком spo в цьому випадку).

Якщо вираз і рядок збігаються, це призводить до істинного і повертає маркер (який є рядком, на який працює оператор переключення).

Очевидно, що маркер === маркер, тому оператор перемикання відповідає і обчислюється випадок

Легше зрозуміти, якщо ви подивитесь на нього шарами і зрозумієте, що тест повороту оцінюється "ДО" ДО "оператора перемикача, щоб вислів коммутатора бачив лише результати тесту.


Ваша відповідь заплутаний. Чи можете ви переглянути та вдосконалити приклад та пояснення?
— фальсарела

@falsarella Я пояснив частину, на яку я уявив, що ти маєш проблеми з розумінням. Я не думаю, що я можу зробити простіший приклад. Якщо у вас є більше запитань або ви можете бути більш конкретними щодо ваших труднощів, я можу допомогти більше.
— Джеймс

Гаразд, тепер я зрозумів. Я був розгублений, тому що очевидно, що token.match(/spo/)відповідатиме.
— фальсарела

3

Це може бути простіше. Спробуйте думати так:

  • спочатку спіймайте рядок між звичайними символами
  • після цього знайдіть "справу"

:

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

Отримано. Але зауважте:TypeError: url.match(...) is null
— 1111161171159459134

1

Може запізнитися і все, але мені це сподобалось у випадку призначення :)

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

ви можете взяти його далі і передати список опцій та обробити регулярний вираз з |


1
Я б також змінив || {}на || [-1]або подібний для безпеки типу. Крім того, чому new RegExpвикористовується, а не тільки косої риси?
— Сергій Красильников

Не дуже знадобився час на його вдосконалення. Момент, коли він працював, я просто продовжував ..... Мені зараз соромно.
— TacB0sS

Не панікуйте, це був лише мій збір азоту;) Насправді я навіть не впевнений, що я правий, я намагався навчитися новому.
— Сергій Красильников

Ні ... ви маєте рацію ... я, безумовно, міг би узагальнити і вдосконалити .. Я, коли знову доберуся до цього коду .., буде досить скоро, сподіваюся :)
— TacB0sS
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.