ฉันคิดว่าน่าจะสนุกที่จะติดตามบทความของเมื่อวานเกี่ยวกับเงื่อนไข regex โดยดูที่ลูกเล่นอื่นๆ ที่คุณสามารถทำได้ด้วยนิพจน์ทั่วไปใน ruby
การแยกสตริงด้วยนิพจน์ทั่วไป
คุณอาจค่อนข้างคุ้นเคยกับการแยกสตริงโดยใช้ตัวคั่นข้อความ:
"one,two".split(",")
# => ["one", "two"]
แต่คุณรู้หรือไม่ว่าการแยกจะยอมรับนิพจน์ทั่วไปด้วย
# use `,` and `-` as delimiters
"one,two-three".split(/,|-/)
=> ["one", "two", "three"]
# Use comma as thousands separator for US currency,
# but use a space for Euros
"1,000USD".split /(?=.*(USD))(?(1),| )/
จับตัวคั่น
นี่คือเคล็ดลับปาร์ตี้ที่เรียบร้อย โดยปกติ เมื่อคุณแยกสตริง ตัวคั่นจะหายไป:
# The commas vanish!
"one,two".split(",")
# => ["one", "two"]
แต่ถ้าคุณใช้นิพจน์ทั่วไปและคุณใส่ตัวคั่นในกลุ่ม split
จะจับตัวคั่นด้วย
"one,two-three".split(/(,|-)/)
=> ["one", ",", "two", "-", "three"]
สาเหตุที่เกิดขึ้นก็คือ split
จริง ๆ แล้วแยกสตริงที่ขอบเขตของกลุ่มดักจับแต่ละกลุ่ม
ละเมิด split
คุณสามารถใช้ split
. ในทางที่ผิด เพื่อให้มีลักษณะเหมือน match
. ในโค้ดด้านล่าง ฉันใช้สี่กลุ่มในนิพจน์ทั่วไปเพื่อแยกสตริงออกเป็น 4 ส่วน
"1-800-555-1212".split(/(1)-(\d{3})-(\d{3})-(\d{4})/)
=> ["", "1", "800", "555", "1212"]
รายการแรกในอาร์เรย์ผลลัพธ์เป็นสตริงว่างเนื่องจากนิพจน์ทั่วไปตรงกับสตริงต้นทางทั้งหมด
การจับคู่ทั่วโลก
โดยค่าเริ่มต้น นิพจน์ทั่วไปจะจับคู่รูปแบบเพียงครั้งเดียว ในโค้ดด้านล่าง เราได้รับเพียงหนึ่งรายการที่ตรงกัน แม้ว่าจะมีการจับคู่ที่เป็นไปได้ห้ารายการ
"12345".match /\d/
=> #<MatchData "1">
ในภาษาอื่นๆ เช่น Perl วิธีแก้ไขคือตั้งค่าสถานะนิพจน์ทั่วไปเป็น "ทั่วโลก" Ruby ไม่มีตัวเลือกนั้น แต่มี String#scan
กระบวนการ.
scan
method ส่งคืนอาร์เรย์ที่มีการแข่งขันทั้งหมด:
"12345".scan /\d/
=> ["1", "2", "3", "4", "5"]
มันยังมีรูปแบบการบล็อกที่สะดวก:
"12345".scan /\d/ do |i|
puts i
end
น่าเสียดายที่ดูเหมือนว่าจะไม่มีวิธีใดในการสแกนสตริงอย่างเกียจคร้าน ดังนั้นเทคนิคนี้อาจไม่เหมาะสำหรับ - พูด - การประมวลผลไฟล์ 500mb
การสแกนด้วยกลุ่ม
ณ จุดนี้ ฉันหวังว่าคุณจะสงสัยว่าเราสามารถใช้กลอุบายแปลก ๆ แบบใดได้บ้างโดยใช้กลุ่มในการสแกนของเรา
น่าเสียดายที่พฤติกรรมที่นี่คาดเดาได้อย่างสมบูรณ์และน่าเบื่อ กลุ่มส่งผลให้อาร์เรย์หลายมิติ:
"hiho hiho".scan /(hi)(ho)/
=> [["hi", "ho"], ["hi", "ho"]]
มีเคสขอบแปลกอยู่หนึ่งเคส หากคุณใช้กลุ่ม สิ่งใดที่ไม่อยู่ในกลุ่มจะไม่ถูกส่งกลับ
"hiho hiho".scan /(hi)ho/
=> [["hi"], ["hi"]]
ชอร์ตแฮนด์
ฉันพนันว่าคุณรู้เกี่ยวกับ =~
เพื่อตรวจสอบว่านิพจน์ทั่วไปตรงกับสตริงหรือไม่ ส่งกลับดัชนีของตัวละครที่การแข่งขันเริ่มต้น
"hiho" =~ /hi/
# 0
"hiho" =~ /ho/
# 2
มีอีกวิธีที่รวดเร็วในการตรวจสอบการจับคู่ ฉันกำลังพูดถึง ===
โอเปอเรเตอร์
/hi/ === "hiho"
# true
เมื่อเราเขียน a === b
ในทับทิมเรากำลังถามว่า "b อยู่ในชุดที่กำหนดโดย a" หรือไม่ หรือในกรณีนี้ "hiho" อยู่ในชุดของสตริงที่จับคู่โดย regex /hi/
".
===
ตัวดำเนินการถูกใช้ภายในในกรณีของ Ruby นั่นหมายความว่า คุณสามารถใช้นิพจน์ทั่วไปในคำสั่ง case ได้เช่นกัน
case "hiho"
when /hi/
puts "match"
end
ตัวดำเนินการเท่ากับสามเท่ายังมีประโยชน์ในการให้เมธอดของคุณยอมรับนิพจน์ทั่วไปหรือสตริงก็ได้
ลองนึกภาพว่าคุณต้องการรันโค้ดบางตัวเมื่อมีข้อผิดพลาดเกิดขึ้น เว้นแต่จะไม่สนใจรายการคลาสที่กำหนดค่าไว้ล่วงหน้า ในตัวอย่างด้านล่าง เราใช้ ===
ตัวดำเนินการเพื่อให้ผู้ใช้สามารถระบุสตริงหรือนิพจน์ทั่วไป
def ignored?(error)
@ignored_patterns.any? { |x| x === error.class.name }
end
แค่นั้น!
เพื่อให้แน่ใจว่ามีเทคนิคเล็กๆ น้อยๆ เช่นนี้กระจายอยู่ทั่ว Ruby and Rails หากมีสิ่งใดที่คุณชอบเป็นพิเศษ แจ้งให้เราทราบ!