Переключити оператор для відповідності рядків у 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.