Chuyển đổi câu lệnh để khớp chuỗi trong JavaScript


193

Làm thế nào để tôi viết một swtich cho điều kiện sau đây?

Nếu url chứa "foo", thì settings.base_url là "bar".

Sau đây là đạt được hiệu quả cần thiết nhưng tôi cảm thấy điều này sẽ dễ quản lý hơn trong một công tắc:

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

Câu trả lời:


352

Bạn không thể làm điều đó switchtrừ khi bạn thực hiện khớp chuỗi đầy đủ ; đó là kết hợp chuỗi con . (Điều này không hoàn toàn đúng, như Sean chỉ ra trong các bình luận. Xem ghi chú ở cuối.)

Nếu bạn hài lòng rằng regex của bạn ở trên cùng đang tước đi mọi thứ mà bạn không muốn so sánh trong trận đấu của mình, bạn không cần một trận đấu chuỗi con và có thể làm:

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

... nhưng một lần nữa, nó chỉ hoạt động nếu đó là chuỗi hoàn chỉnh mà bạn khớp. Sẽ là thất bại nếu base_url_string, nói, "yyy.xxx.local" trong khi mã hiện tại của bạn sẽ khớp với mã trong nhánh "xxx.local".


Cập nhật : Được rồi, về mặt kỹ thuật, bạn có thể sử dụng switchkết hợp chuỗi con, nhưng tôi không khuyên dùng nó trong hầu hết các tình huống. Đây là cách ( ví dụ trực tiếp ):

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

Điều đó hoạt động vì cách hoạt động của các switchcâu lệnh JavaScript , đặc biệt là hai khía cạnh chính: Thứ nhất, các trường hợp được xem xét theo thứ tự văn bản nguồn và thứ hai là các biểu thức chọn (các bit sau từ khóa case) là các biểu thức được đánh giá như trường hợp đó đánh giá (không phải hằng số như trong một số ngôn ngữ khác). Vì vậy, vì biểu thức kiểm tra của chúng tôi là true, casebiểu thức đầu tiên có kết quả truesẽ là biểu thức được sử dụng.


91
Tôi biết nó đã cũ, nhưng điều này không hoàn toàn đúng - bạn thực sự có thể làmswitch(true) { case /foo/.test(bar): ....
Sean Kinsey

23
Trời ơi, không! Tuyên bố chuyển đổi không phải là để làm việc như vậy. Điều này chỉ đơn giản là bị hỏng, nó là bất hợp pháp để làm những thứ như vậy.
Pijusn

47
Hoohoo, ngon quá ác.
MP Aditya

41
Tất cả các bạn chỉ cần mở rộng quan điểm của bạn. Đây là chuẩn mực trong Ruby, ngoại trừ thay vì có sự xấu xí trueở đó, bạn chỉ cần bỏ nó lại với nhau.
emkman

49
Tôi thích điều này và tôi không xấu hổ khi thừa nhận nó.
vui mừng

65

RegExp có thể được sử dụng trên chuỗi đầu vào không chỉ về mặt kỹ thuật mà còn thực tế với matchphương thức.

Bởi vì đầu ra của match()là một mảng, chúng ta cần lấy phần tử mảng đầu tiên của kết quả. Khi trận đấu thất bại, chức năng trở lại null. Để tránh lỗi ngoại lệ, chúng tôi sẽ thêm ||toán tử điều kiện trước khi truy cập phần tử mảng đầu tiên và kiểm tra thuộc inputtính là thuộc tính tĩnh của các biểu thức chính quy có chứa chuỗi đầu vào.

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

Một cách tiếp cận khác là sử dụng hàm String()tạo để chuyển đổi mảng kết quả chỉ có 1 phần tử (không có nhóm bắt giữ) và toàn bộ chuỗi phải được ghi lại bằng quanitifier ( .*) thành chuỗi. Trong trường hợp thất bại, nullđối tượng sẽ trở thành một "null"chuỗi. Không tiện lợi.

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

Dù sao, một giải pháp thanh lịch hơn là sử dụng phương thức /^find-this-in/.test(str)with switch (true)chỉ đơn giản trả về giá trị boolean và dễ dàng tìm kiếm hơn mà không có phân biệt chữ hoa chữ thường.


1
pribilinsiky: có lẽ bạn nên đề cập rằng giải pháp thứ ba của bạn (sử dụng test ()) yêu cầu bạn phải có công tắc (đúng).
ngày

35

Chỉ cần sử dụng thuộc tính location.host

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

1
Cảm ơn, +1 vì đây là điều tôi nên làm thực sự
Tiến sĩ Frankenstein

Bạn phải quan tâm đến loại biến bạn chuyển sang câu lệnh switch. Nó phải là một chuỗi. Để chắc chắn bạn có thể làm switch ("" + location.host).
ceving

16

Một tùy chọn khác là sử dụng inputtrường của kết quả khớp regex :

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

tốt đẹp Trong trường hợp này, bất kỳ thuộc tính mảng nào cũng có thể được sử dụng để kiểm tra, ví dụ:.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;;
}


-> Nếu kết quả khớp được thực hiện, biểu thức ternary trả về mã thông báo gốc
----> Mã thông báo ban đầu được đánh giá theo trường hợp

-> Nếu trận đấu không được thực hiện, trả về ternary không xác định
----> Case đánh giá mã thông báo so với không xác định mà hy vọng mã thông báo của bạn không.

Thử nghiệm ternary có thể là bất cứ điều gì trong trường hợp của bạn

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

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

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

là một biểu hiện ternary.

Thử nghiệm trong trường hợp này là token.match (/ spo /) trong đó nêu rõ chuỗi khớp được giữ trong mã thông báo so với biểu thức regex / spo / (là chuỗi spo theo nghĩa đen trong trường hợp này).

Nếu biểu thức và chuỗi khớp với nó, kết quả là true và trả về mã thông báo (là chuỗi mà câu lệnh switch đang hoạt động).

Rõ ràng mã thông báo === mã thông báo để câu lệnh chuyển đổi được khớp và trường hợp được đánh giá

Sẽ dễ hiểu hơn nếu bạn nhìn vào nó trong các lớp và hiểu rằng kiểm tra quay vòng được đánh giá "TRƯỚC" câu lệnh chuyển đổi để câu lệnh chuyển đổi chỉ nhìn thấy kết quả của bài kiểm tra.


Câu trả lời của bạn thật khó hiểu. Bạn có thể xem lại và cải thiện ví dụ và giải thích?
falsarella

@falsarella Tôi đã giải thích phần tôi tưởng tượng bạn gặp khó khăn trong việc hiểu. Tôi không nghĩ rằng tôi có thể làm một ví dụ đơn giản hơn. Nếu bạn có nhiều câu hỏi hơn hoặc có thể cụ thể hơn với những khó khăn của bạn, tôi có thể giúp đỡ nhiều hơn.
James

Ok, bây giờ tôi đã nhận nó. Tôi đã bối rối vì rõ ràng là token.match(/spo/)sẽ phù hợp.
falsarella

3

Nó có thể dễ dàng hơn. Hãy thử nghĩ như thế này:

  • đầu tiên bắt một chuỗi giữa các ký tự thông thường
  • sau đó tìm "trường hợp"

:

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

Nâng cao. Nhưng lưu ý:TypeError: url.match(...) is null
1111161171159459134

1

Có thể là quá muộn và tất cả, nhưng tôi thích điều này trong trường hợp chuyển nhượng :)

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

bạn có thể đưa sự kiện đi xa hơn và vượt qua danh sách tùy chọn và xử lý biểu thức chính quy với |


1
Tôi cũng muốn thay đổi || {}để || [-1]hoặc tương tự cho loại an toàn. Ngoài ra, tại sao được new RegExpsử dụng, không chỉ là dấu gạch chéo?
Sergey Krasnilnikov

Tôi đã không thực sự dành thời gian để tinh chỉnh nó .. thời điểm nó hoạt động tôi chỉ tiếp tục ..... Tôi cảm thấy xấu hổ bây giờ.
TacB0sS

Đừng hoảng sợ, đó chỉ là sự lựa chọn nit của tôi;) Thực tế tôi thậm chí không chắc là mình đúng, tôi đã cố gắng học hỏi thứ mới.
Sergey Krasnilnikov

Không ... bạn đúng ... Tôi chắc chắn có thể đã khái quát hóa và làm đẹp .. Tôi sẽ khi tôi nhận được mã đó một lần nữa .. tôi sẽ sớm thôi :)
TacB0sS
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.