สลับคำสั่งสำหรับการจับคู่สตริงใน 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จนกว่าคุณจะทำการจับคู่สตริงเต็ม กำลังทำการจับคู่สตริงย่อย (สิ่งนี้ไม่เป็นความจริงอย่างที่ฌอนชี้ให้เห็นในความคิดเห็นดูหมายเหตุท้าย)

หากคุณมีความสุขที่ regex ของคุณอยู่ด้านบนลอกทุกอย่างที่คุณไม่ต้องการเปรียบเทียบในการแข่งขันของคุณคุณไม่จำเป็นต้องจับคู่สตริงย่อยและสามารถทำได้:

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): ....
Sean Kinsey

23
โอ้พระเจ้าไม่! คำสั่ง Switch ไม่ควรทำงานอย่างนั้น สิ่งนี้แตกง่ายควรทำสิ่งผิดกฎหมาย
Pijusn

47
Hoohoo ชั่วร้ายโอชะ
Aditya MP

41
คุณทุกคนต้องขยายมุมมองของคุณ นี่เป็นบรรทัดฐานในทับทิมยกเว้นแทนที่จะมีคนน่าเกลียดtrueอยู่ที่นั่นคุณแค่ปล่อยมันไปด้วยกัน
emkman

49
ฉันรักสิ่งนี้และฉันไม่ละอายที่จะยอมรับ
chrisf

65

RegExp สามารถใช้กับสตริงอินพุตไม่เพียง แต่ในทางเทคนิค แต่ในทางปฏิบัติกับmatchวิธีการเช่นกัน

เนื่องจากผลลัพธ์ของmatch()a คืออาร์เรย์เราจำเป็นต้องดึงข้อมูลองค์ประกอบอาร์เรย์แรกของผลลัพธ์ เมื่อการแข่งขันล้มเหลวฟังก์ชันจะกลับ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 องค์ประกอบ (ไม่มีกลุ่มการจับ) และสตริงทั้งหมดจะต้องถูกจับด้วย quanitifiers ( .*) เป็นสตริง ในกรณีของความล้มเหลว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)ด้วยswitch (true)ซึ่งส่งคืนค่าบูลีนและค้นหาได้ง่ายขึ้นโดยไม่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่


1
pribilinsiky: คุณอาจจะพูดถึงว่าวิธีที่สามของคุณ (โดยใช้การทดสอบ ()) ต้องการให้คุณเปลี่ยน (จริง)
traday

35

เพียงใช้คุณสมบัติ location.host

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

1
ขอบคุณ +1 เพราะนี่คือสิ่งที่ฉันควรทำจริงๆ
ดร. แฟรงเกนสไตน์

คุณต้องดูแลเกี่ยวกับประเภทของตัวแปรที่คุณส่งไปยังคำสั่ง switch มันจะต้องเป็นสตริง switch ("" + location.host)เพื่อให้แน่ใจว่าคุณสามารถทำได้
เซเว่น

16

ตัวเลือกอื่นคือใช้inputฟิลด์ของผลลัพธ์การจับคู่ 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;
}

ทำได้ดีนี่. ในกรณีนี้คุณสมบัติอาเรย์ใด ๆ ก็สามารถใช้สำหรับการทดสอบเช่น.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;;
}


-> หากการจับคู่เกิดขึ้นนิพจน์ประกอบไปด้วยจะส่งคืนโทเค็นดั้งเดิม
----> โทเค็นดั้งเดิมจะถูกประเมินโดยตัวพิมพ์

-> หากการแข่งขันไม่ได้ทำ ternary จะคืนค่า undefined
----> Case จะประเมินโทเค็นกับ undefined ซึ่งหวังว่าโทเค็นของคุณจะไม่

การทดสอบแบบไตรภาคสามารถเป็นตัวอย่างในกรณีของคุณได้

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

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

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

เป็นการแสดงออกที่ไตรภาค

การทดสอบในกรณีนี้คือ token.match (/ spo /) ซึ่งระบุการจับคู่สตริงที่อยู่ในโทเค็นกับนิพจน์ regex / spo / (ซึ่งเป็นสตริงตัวอักษร spo ในกรณีนี้)

หากนิพจน์และสตริงตรงกันผลลัพธ์จะเป็นจริงและส่งคืนโทเค็น (ซึ่งเป็นสตริงที่คำสั่ง switch ทำงานอยู่)

โทเค็นอย่างชัดเจน === โทเค็นเพื่อให้คำสั่งสวิตช์ถูกจับคู่และตัวพิมพ์เล็กประเมิน

เป็นการง่ายกว่าที่จะเข้าใจถ้าคุณดูในเลเยอร์และเข้าใจว่าการทดสอบแบบหมุนได้รับการประเมิน "ก่อน" คำสั่งสลับเพื่อให้คำสั่งสลับเท่านั้นเห็นผลลัพธ์ของการทดสอบ


คำตอบของคุณสับสน คุณสามารถตรวจสอบและปรับปรุงตัวอย่างและคำอธิบายได้หรือไม่
falsarella

@falsarella ฉันอธิบายส่วนที่ฉันจินตนาการว่าคุณมีปัญหาในการทำความเข้าใจ ฉันไม่คิดว่าฉันจะเป็นตัวอย่างที่ง่ายกว่านี้ได้ หากคุณมีคำถามเพิ่มเติมหรือเฉพาะเจาะจงมากขึ้นกับปัญหาของคุณฉันสามารถช่วยได้มาก
James

ตกลงตอนนี้ฉันเข้าใจแล้ว ฉันสับสนเพราะเห็นได้ชัดว่าtoken.match(/spo/)จะจับคู่
falsarella

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

upvoted แต่หมายเหตุ: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;
        }
    });
};

คุณสามารถจัดอีเวนต์เพิ่มเติมและส่งรายการตัวเลือกและจัดการ regex ด้วย |


1
ฉันจะเปลี่ยน|| {}เป็น|| [-1]หรือคล้ายกันเพื่อความปลอดภัยประเภท นอกจากนี้ทำไมมีการnew RegExpใช้งานไม่ใช่แค่เครื่องหมายทับ?
Sergey Krasilnikov

ไม่ได้ใช้เวลาในการปรับแต่งจริงๆ ... ช่วงเวลาที่มันทำงานฉันเพิ่งดำเนินการต่อ ..... ฉันรู้สึกละอายในขณะนี้
TacB0sS

อย่าตกใจนั่นเป็นเพียงการหยิบยกของฉัน;) อันที่จริงฉันไม่แน่ใจด้วยซ้ำว่าถูกต้องฉันพยายามเรียนรู้เรื่องใหม่
Sergey Krasilnikov

ไม่ ... คุณถูกต้อง ... ฉันสามารถสร้างและทำให้ดีขึ้นได้แน่นอน .. ฉันจะทำอย่างไรเมื่อฉันได้รับรหัสนั้นอีกครั้ง .. จะเร็วพอที่ฉันหวังว่า :)
23919
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.