Ganti pernyataan untuk pencocokan string dalam JavaScript

193

Bagaimana saya menulis swtich untuk persyaratan berikut?

Jika url berisi "foo", maka settings.base_url adalah "bar".

Berikut ini adalah mencapai efek yang diperlukan tetapi saya merasa ini akan lebih mudah dikelola dalam suatu pergantian:

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

Jawaban:

352

Anda tidak dapat melakukannya di switchkecuali Anda melakukan pencocokan string penuh ; itu melakukan pencocokan substring . (Ini tidak cukup benar, seperti yang ditunjukkan Sean dalam komentar. Lihat catatan di bagian akhir.)

Jika Anda senang bahwa regex Anda di atas menghilangkan semua yang tidak ingin Anda bandingkan dalam pertandingan Anda, Anda tidak perlu pertandingan substring, dan dapat melakukan:

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

... tapi sekali lagi, itu hanya berfungsi jika itu adalah string lengkap yang cocok dengan Anda. Itu akan gagal jika base_url_string, katakanlah, "yyy.xxx.local" sedangkan kode Anda saat ini akan cocok dengan yang ada di cabang "xxx.local".


Pembaruan : Oke, jadi secara teknis Anda dapat menggunakan switchpencocokan substring, tetapi saya tidak akan merekomendasikannya di sebagian besar situasi. Begini caranya ( contoh langsung ):

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

Itu berfungsi karena cara switchkerja pernyataan JavaScript , khususnya dua aspek utama: Pertama, bahwa kasus dipertimbangkan dalam urutan teks sumber , dan kedua bahwa ekspresi pemilih (bit setelah kata kunci case) adalah ekspresi yang dievaluasi sebagaimana halnya case dievaluasi (bukan konstanta seperti dalam beberapa bahasa lain). Jadi karena ekspresi pengujian kami adalah true, caseekspresi pertama yang menghasilkan trueakan menjadi yang digunakan.

TJ Crowder
sumber
91
Saya tahu ini sudah tua, tetapi ini tidak sepenuhnya benar - Anda dapat melakukannyaswitch(true) { case /foo/.test(bar): ....
Sean Kinsey
23
Ya Tuhan, tidak! Pernyataan pergantian tidak seharusnya bekerja seperti itu. Ini hanya rusak, harus ilegal untuk melakukan hal-hal seperti itu.
Pijusn
47
Hoohoo, kejahatannya begitu nikmat.
Aditya MP
41
Anda semua hanya perlu memperluas perspektif Anda. Ini adalah norma di Ruby, kecuali alih-alih memiliki jelek di truesana, Anda hanya meninggalkannya bersama-sama.
emkman
49
Saya suka ini dan saya tidak malu mengakuinya.
chrisf
65

RegExp dapat digunakan pada string input tidak hanya secara teknis tetapi juga praktis dengan matchmetode ini.

Karena output dari match()array, kita perlu mengambil elemen array pertama dari hasilnya. Ketika pertandingan gagal, fungsi kembali null. Untuk menghindari kesalahan pengecualian, kami akan menambahkan ||operator kondisional sebelum mengakses elemen array pertama dan menguji inputproperti yang merupakan properti statis dari ekspresi reguler yang berisi string 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;
}

Pendekatan lain adalah dengan menggunakan String()konstruktor untuk mengkonversi array yang dihasilkan yang harus memiliki hanya 1 elemen (tidak ada grup penangkap) dan seluruh string harus ditangkap dengan quanitifiers ( .*) ke string. Dalam hal terjadi kegagalan nullobjek akan menjadi "null"string. Tidak mudah.

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

Bagaimanapun, solusi yang lebih elegan adalah menggunakan metode /^find-this-in/.test(str)with switch (true)yang hanya mengembalikan nilai boolean dan lebih mudah untuk mencari tanpa sensitivitas case.

Steven Pribilinskiy
sumber
1
pribilinsiky: Anda mungkin harus menyebutkan bahwa solusi ketiga Anda (menggunakan test ()) mengharuskan Anda untuk beralih (benar).
Traday
35

Cukup gunakan properti location.host

switch (location.host) {
    case "xxx.local":
        settings = ...
        break;
    case "xxx.dev.yyy.com":
        settings = ...
        break;
}
Sean Kinsey
sumber
1
Terima kasih, +1 karena inilah yang seharusnya saya lakukan
Dr. Frankenstein
Anda harus berhati-hati tentang tipe variabel yang Anda berikan ke pernyataan switch. Itu harus berupa string. Yang pasti bisa Anda lakukan switch ("" + location.host).
ceving
16

Pilihan lain adalah menggunakan inputbidang hasil pertandingan 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
sumber
bagus Dalam hal ini properti array apa pun juga dapat digunakan untuk pengujian, misalnya.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;;
}


-> Jika kecocokan dibuat, ekspresi ternary mengembalikan token asli
----> Token asli dievaluasi berdasarkan kasus

-> Jika pertandingan tidak membuat pengembalian terner tidak terdefinisi
----> Case mengevaluasi token terhadap undefined yang diharapkan token Anda tidak.

Tes ternary dapat berupa apa saja misalnya dalam kasus Anda

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

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

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

adalah ekspresi ternary.

Pengujian dalam kasus ini adalah token.match (/ spo /) yang menyatakan kecocokan string yang dipegang dalam token terhadap ekspresi regex / spo / (yang merupakan spo string literal dalam kasus ini).

Jika ekspresi dan string cocok dengan itu menghasilkan true dan mengembalikan token (yang merupakan string pernyataan switch beroperasi).

Jelas token === token sehingga pernyataan switch cocok dan case dievaluasi

Lebih mudah untuk dipahami jika Anda melihatnya berlapis-lapis dan memahami bahwa uji turnery dievaluasi "SEBELUM" pernyataan switch sehingga pernyataan switch hanya melihat hasil tes.

James
sumber
Jawaban Anda membingungkan. Bisakah Anda meninjau dan meningkatkan contoh dan penjelasannya?
falsarella
@ falsarella saya menjelaskan bagian yang saya bayangkan Anda mengalami kesulitan memahami. Saya rasa saya tidak bisa membuat contoh yang lebih sederhana. Jika Anda memiliki lebih banyak pertanyaan atau dapat lebih spesifik dengan kesulitan Anda, saya dapat membantu lebih banyak.
James
Ok, sekarang saya mengerti. Saya bingung karena jelas yang token.match(/spo/)cocok.
falsarella
3

Mungkin lebih mudah. Cobalah untuk berpikir seperti ini:

  • pertama menangkap string antara karakter biasa
  • setelah itu cari "case"

:

// '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
sumber
Terpilih. Tetapi perhatikan:TypeError: url.match(...) is null
1111161171159459134
1

Mungkin sudah terlambat dan semuanya, tapi saya suka tugas jaga ini :)

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

Anda dapat mengambilnya lebih jauh, dan memberikan daftar opsi dan menangani regex dengan |

TacB0sS
sumber
1
Saya juga akan mengubah || {}ke || [-1]atau serupa untuk jenis keamanan. Juga, mengapa new RegExpdigunakan, bukan hanya tebasan?
Sergey Krasilnikov
tidak benar-benar meluangkan waktu untuk memperbaikinya .. saat itu berhasil saya hanya melanjutkan ..... saya merasa malu sekarang.
TacB0sS
Jangan panik, itu hanya kesalahan saya;) Sebenarnya saya bahkan tidak yakin saya benar, saya mencoba belajar sesuatu yang baru.
Sergey Krasilnikov
Tidak ... Anda benar ... Saya pasti bisa membuat dan membuat cantik .. Saya akan ketika saya mendapatkan kode itu lagi .. akan segera saya harap :)
TacB0sS