จะเขียนคำสั่ง Ruby switch (case … when) ด้วย regex และ backreferences ได้อย่างไร?


89

ฉันรู้ว่าฉันสามารถเขียนคำสั่งกรณี Ruby เพื่อตรวจสอบการจับคู่กับนิพจน์ทั่วไป อย่างไรก็ตามฉันต้องการใช้ข้อมูลที่ตรงกันในคำสั่งส่งคืนของฉัน บางอย่างเช่นรหัสกึ่งเทียมนี้:

foo = "10/10/2011"

case foo
    when /^([0-9][0-9])/
        print "the month is #{match[1]}"
    else
        print "something else"
end

ฉันจะบรรลุสิ่งนั้นได้อย่างไร?

ขอบคุณ!


หมายเหตุ: ฉันเข้าใจว่าฉันจะไม่ใช้คำสั่ง switch สำหรับกรณีธรรมดา ๆ ข้างต้น แต่นั่นเป็นเพียงตัวอย่างเดียว ในความเป็นจริงสิ่งที่ฉันพยายามจะบรรลุคือการจับคู่นิพจน์ทั่วไปที่เป็นไปได้สำหรับวันที่ซึ่งสามารถเขียนได้หลายวิธีจากนั้นแยกวิเคราะห์ด้วยคลาส Date ของ Ruby ตามลำดับ


1
Date.parse ของ Ruby เข้าใจรูปแบบวันที่มากมาย คุณลองหรือยัง?
ฝนตก

แม้ว่าจะไม่ตอบคำถามนี้ แต่คุณอาจต้องการดู Chronic gem ...
DGM

คำตอบ:


156

การอ้างอิงถึงกลุ่มการจับคู่ regex ล่าสุดจะถูกเก็บไว้ในตัวแปรหลอก เสมอ$1เพื่อ$9:

case foo
when /^([0-9][0-9])/
    print "the month is #{$1}"
else
    print "something else"
end

คุณยังสามารถใช้$LAST_MATCH_INFOตัวแปรหลอกเพื่อรับที่MatchDataวัตถุทั้งหมด สิ่งนี้จะมีประโยชน์เมื่อใช้แคปเจอร์ตามชื่อ:

case foo
when /^(?<number>[0-9][0-9])/
    print "the month is #{$LAST_MATCH_INFO['number']}"
else
    print "something else"
end

1
@Yossi คุณมีแหล่งที่มาสำหรับความคิดเห็นของคุณเกี่ยวกับความปลอดภัยของด้ายหรือไม่? ฉันเพิ่งทำการทดลองกับทับทิม 1.8.7 ซึ่งดูเหมือนจะบ่งชี้ว่าปลอดภัยต่อเกลียว! (เธรดที่จับคู่ regex ทุก ๆ หนึ่งวินาที - ตรวจสอบใน irb ว่าการแข่งขันในพื้นที่มีการกระจุกตัวหรือไม่)
Joel

5
ตัวแปร -1 $ ที่เกี่ยวข้องกับนิพจน์ทั่วไปนั้นไม่ได้เป็นแบบสากลแม้ว่าจะมีเครื่องหมายดอลลาร์อยู่ข้างหน้าก็ตาม
Andrew Grimm

@AndrewGrimm ขอบคุณที่ชี้ให้เห็น ฉันไม่ได้ตระหนักถึงมัน ฉันจะต้องเปลี่ยนรหัสเก่าจำนวนมาก: - /
Yossi

นอกจากนี้คุณยังสามารถทำ$1, $2... $9หรือRegexp.last_match(1)ตามคำแนะนำของ rubocop
เอ็ดการ์กาซา

6

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

res = [ /pat1/, /pat2/, ... ]
m   = nil
res.find { |re| m = foo.match(re) }
# Do what you will with `m` now.

การประกาศmนอกบล็อกช่วยให้ยังสามารถใช้งานได้หลังจากfindเสร็จสิ้นกับบล็อกและfindจะหยุดทันทีที่บล็อกส่งคืนค่าที่แท้จริงเพื่อให้คุณได้รับลักษณะการทำงานทางลัดแบบเดียวกับที่สวิตช์ให้คุณ สิ่งนี้ให้คุณได้เต็มที่MatchDataหากคุณต้องการ (บางทีคุณอาจต้องการใช้กลุ่มการจับข้อมูลที่มีชื่อใน regexes ของคุณ) และแยก regexes ของคุณออกจากตรรกะการค้นหาของคุณอย่างดี (ซึ่งอาจให้รหัสที่ชัดเจนกว่าหรือไม่ก็ได้) คุณสามารถโหลด regexes ของคุณจาก a config ไฟล์หรือเลือกชุดของพวกเขาที่คุณต้องการในขณะทำงาน


ฉันยังคิดเกี่ยวกับความปลอดภัยของด้ายโดยใช้caseวิธีนี้ บางทีคุณอาจต้องการใช้แนวทางของ mu ในสถานการณ์ที่มีเธรดแทนที่จะเป็นตัวแปรส่วนกลางด้วยวิธีเคส (?)
Casper
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.