แยกสตริงย่อยจากสตริงใน Ruby โดยใช้นิพจน์ปกติ


130

ฉันจะแยกสตริงย่อยจากภายในสตริงใน Ruby ได้อย่างไร

ตัวอย่าง:

String1 = "<name> <substring>"

ฉันต้องการแยกsubstringจากString1(เช่นทุกอย่างภายในเหตุการณ์ล่าสุด<และ>)

คำตอบ:


134
String1.scan(/<([^>]*)>/).last.first

scanสร้างอาร์เรย์ซึ่งสำหรับแต่ละ<item>ในString1ประกอบด้วยข้อความระหว่าง<และ>ในอาร์เรย์หนึ่งองค์ประกอบ (เพราะเมื่อใช้กับ regex ที่มีกลุ่มจับสแกนสร้างอาร์เรย์ที่มีการจับภาพสำหรับการแข่งขันแต่ละครั้ง) lastให้คุณสุดท้ายของอาร์เรย์เหล่าfirstนั้นแล้วให้สายในนั้น


319
"<name> <substring>"[/.*<([^>]*)/,1]
=> "substring"

ไม่จำเป็นต้องใช้scanถ้าเราต้องการเพียงผลเดียว
ไม่จำเป็นต้องใช้งูใหญ่เมื่อเรามีทับทิมmatchString[regexp,#]

ดู: http://ruby-doc.org/core/String.html#method-i-5B-5D

บันทึก: str[regexp, capture] → new_str or nil


37
ไม่จำเป็นต้องทำให้เสียชื่อเสียงอื่น ๆ ที่ถูกต้องสมบูรณ์แบบ
coreyward

41
@ แกนไปข้างหน้าถ้าพวกเขาดีกว่าโปรดโต้แย้งมัน ตัวอย่างเช่นโซลูชันของ sepp2k นั้นยืดหยุ่นกว่าและนั่นคือสาเหตุที่ฉันชี้ไปที่if we need only one resultโซลูชัน และmatch()[]ช้าลงเพราะเป็นสองวิธีแทนที่จะเป็นหนึ่งวิธี
Nakilon

4
นี่เป็นวิธีที่เร็วที่สุดของวิธีการทั้งหมดที่นำเสนอ แต่แม้กระทั่งวิธีที่ช้าที่สุดก็ใช้เวลาเพียง 4.5 microseconds ในเครื่องของฉัน ฉันไม่สนใจที่จะคาดเดาว่าทำไมวิธีนี้จึงเร็วขึ้น ในการปฏิบัติงานการเก็งกำไรเป็นไร้ประโยชน์ นับเฉพาะการวัดเท่านั้น
Wayne Conrad

8
ฉันพบโซลูชันนี้ตรงไปตรงมามากขึ้นและตรงประเด็น (ตั้งแต่ฉันใหม่กับ Ruby) ขอบคุณ
Ryan H.

@Nakilon Readability สามารถทำให้ประสิทธิภาพแตกต่างกันเล็กน้อยเมื่อพิจารณาถึงความสำเร็จโดยรวมของผลิตภัณฑ์และทีมดังนั้น coreyward จึงแสดงความคิดเห็นที่ถูกต้อง ที่กล่าวว่าฉันคิดว่าstring[regex]สามารถอ่านได้ในสถานการณ์นี้ดังนั้นนั่นคือสิ่งที่ฉันใช้เป็นการส่วนตัว
นิค

24

คุณสามารถใช้การแสดงออกปกติสำหรับที่สวยได้อย่างง่ายดาย ...

การอนุญาตให้มีช่องว่างรอบคำ (แต่ไม่ได้ทำให้พวกเขา):

str.match(/< ?([^>]+) ?>\Z/)[1]

หรือไม่มีช่องว่างที่อนุญาต:

str.match(/<([^>]+)>\Z/)[1]

1
ฉันไม่แน่ใจว่าสิ่งสุดท้ายที่<>จริงจะต้องเป็นสิ่งสุดท้ายในสตริง ถ้าเช่นสตริงfoo <bar> bazอนุญาต (และควรให้ผลลัพธ์bar) สิ่งนี้จะไม่ทำงาน
sepp2k

ฉันไปตามสตริงตัวอย่างที่เขาให้ไว้
coreyward

10

นี่เป็นวิธีที่ยืดหยุ่นกว่าเล็กน้อยโดยใช้matchวิธีนี้ ด้วยสิ่งนี้คุณสามารถแยกมากกว่าหนึ่งสตริง:

s = "<ants> <pants>"
matchdata = s.match(/<([^>]*)> <([^>]*)>/)

# Use 'captures' to get an array of the captures
matchdata.captures   # ["ants","pants"]

# Or use raw indices
matchdata[0]   # whole regex match: "<ants> <pants>"
matchdata[1]   # first capture: "ants"
matchdata[2]   # second capture: "pants"

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