วิธีมาตรฐานของการตัดแต่งสตริงใน Ruby โดยไม่สร้างสตริงใหม่คืออะไร


182

นี่คือสิ่งที่ฉันมีตอนนี้ - ซึ่งดูละเอียดเกินไปสำหรับงานที่กำลังทำอยู่

@title        = tokens[Title].strip! || tokens[Title] if !tokens[Title].nil?

สมมติว่าโทเค็นเป็นอาร์เรย์ที่ได้รับจากการแยกบรรทัด CSV ตอนนี้ฟังก์ชั่นเช่นแถบ! chomp! et ส่งคืนศูนย์ทั้งหมดหากสตริงไม่ได้ถูกแก้ไข

"abc".strip!    # => nil
" abc ".strip!  # => "abc"

อะไรคือวิธีทับทิมที่จะพูดเล็มถ้ามันมีช่องว่างนำหน้าหรือต่อท้ายโดยไม่ต้องสร้างสำเนา?

รับค่าผิดปกติถ้าฉันต้องการทำ tokens[Title].chomp!.strip!


3
หากคุณกำลังจะอ่านสิ่งต่าง ๆ จากโทเค็นซ้ำ ๆ มันอาจเหมาะสมกว่าที่จะประมวลผลล่วงหน้า นั่นคือ "tokens.each {| t | t.strip!}" จากนั้นคุณสามารถทำ "@title = tokens [Title] || ''"
glenn mcdonald

คำตอบ:


272

ฉันเดาว่าคุณต้องการอะไร:

@title = tokens[Title]
@title.strip!

#strip!วิธีการจะกลับมาnilถ้ามันไม่ได้ตัดอะไรและตัวแปรของตัวเองถ้ามันถูกปล้น

ตามมาตรฐานของ Ruby เมธอดที่ต่อท้ายด้วยเครื่องหมายอัศเจรีย์จะเปลี่ยนตัวแปรให้อยู่ในตำแหน่ง

หวังว่านี่จะช่วยได้

อัปเดต:นี่คือผลลัพธ์จากirbเพื่อสาธิต:

>> @title = "abc"
=> "abc"
>> @title.strip!
=> nil
>> @title
=> "abc"
>> @title = " abc "
=> " abc "
>> @title.strip!
=> "abc"
>> @title
=> "abc"

1
อืม .. ฉันยังคิดว่า @title = tokens [Title] .strip! ดูสะอาด - มันน่าเสียดายที่มันส่งกลับศูนย์แทนสตริงที่ไม่ได้แก้ไข ถ้าไม่มีใครโพสต์คำตอบได้ดีกว่า .. คุณจะได้รับการตอบรับที่ดี
Gishu

7
เอาล่ะ @title = tokens [Title] .strip จะทำตามคำสั่ง แต่คุณมีสำเนาแทนซึ่งถือว่าใช้ได้ถ้าคุณเก็บตัวแปร [Title] ไว้ไม่ถูกแตะต้อง
Igor

9
Ruby 1.9 มีการแตะซึ่งทำสิ่งที่คุณต้องการ: @ title.tap {| x | x.strip!}
timkay

2
@timkay เป็นไปได้ไหมที่จะทำ@title.tap &:strip!? ที่ดูสะอาดกว่าสิ่งอื่นใด
Jon Egeland

16
ทำไมในโลกที่มันจะกลับมาnilเว้นแต่จะมีบางสิ่งบางอย่าง? ไม่ต้องสงสัยเลยว่าคนจำนวนมากสับสน (เพราะมันไม่มีเหตุผล)
Josh M.

53

Btw ตอนนี้ ruby ​​รองรับแล้วก็แค่ไม่ใช้ "!"

เปรียบเทียบ:

p "abc".strip! == " abc ".strip!  # false, because "abc".strip! will return nil
p "abc".strip == " abc ".strip    # true

นอกจากนี้ยังเป็นไปไม่ได้stripหากไม่มีข้อมูลซ้ำซ้อน ดูแหล่งที่มาใน string.c:

static VALUE
rb_str_strip(VALUE str)
{
    str = rb_str_dup(str);
    rb_str_strip_bang(str);
    return str;
}

ruby 1.9.3p0 (2011-10-30) [i386-mingw32]

อัปเดต 1: อย่างที่ฉันเห็นตอนนี้มันถูกสร้างขึ้นในปี 1999 ปี (ดูrev # 372ใน SVN):

Update2: strip!จะไม่สร้างรายการซ้ำ - ทั้งในรุ่น 1.9.x, 2.x และรุ่น trunk


1
"มันเป็นไปไม่ได้ที่จะลอกโดยไม่มีการซ้ำซ้อน" - แน่นอนว่าเป็นไปได้นั่นคือสิ่งที่strip!มีไว้สำหรับ
Karoly Horvath

@ KarolyHorvath ไม่ 'คุณเห็นรหัสที่มาเขียนใน C? กรุณาอ่านอย่างละเอียดสิ่งที่ฉันเขียนที่นี่เกี่ยวกับรายการที่ซ้ำกัน
gaRex

1
แน่นอนฉันเห็นมัน stripแต่นั่นเป็นรหัสที่มาของ ฉันเข้าใจผิดบางอย่างหรือไม่? ฉันจะตีความ "ไม่สามารถลอกโดยไม่ทำซ้ำได้อย่างไร"
Karoly Horvath

@KarolyHorvath ซ้ำกันภายในถูกสร้างขึ้นเสมอ นั่นเป็นเรื่องของสตริง `str = rb_str_dup (str);`
gaRex

1
และถ้าคุณไม่ต้องการให้ซ้ำกันคุณใช้akastrip! rb_str_strip_bang
Karoly Horvath

9

ไม่จำเป็นต้องใช้ทั้งแถบและ chomp เนื่องจากแถบจะลบการส่งคืนส่วนท้ายของรถลาก - ยกเว้นว่าคุณได้เปลี่ยนตัวคั่นเร็กคอร์ดเริ่มต้นและนั่นคือสิ่งที่คุณกำลังส่งสัญญาณ

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

def strip_or_self!(str)
  str.strip! || str
end

ให้:

@title = strip_or_self!(tokens[Title]) if tokens[Title]

โปรดทราบว่าคำสั่ง if จะป้องกันไม่ให้@titleถูกกำหนดหากโทเค็นเป็นศูนย์ซึ่งจะส่งผลให้มันรักษาค่าก่อนหน้านี้ หากคุณต้องการหรือไม่คำนึงถึง@titleการมอบหมายคุณสามารถย้ายเช็คไปที่เมธอดและลดการทำซ้ำ:

def strip_or_self!(str)
  str.strip! || str if str
end

เป็นอีกทางเลือกหนึ่งถ้าคุณรู้สึกอยากผจญภัยคุณสามารถกำหนดวิธีบน String ได้:

class String
  def strip_or_self!
    strip! || self
  end
end

ให้หนึ่งใน:

@title = tokens[Title].strip_or_self! if tokens[Title]

@title = tokens[Title] && tokens[Title].strip_or_self!

9

หากคุณกำลังใช้ Ruby on Rails จะมีsquish

> @title = " abc "
 => " abc " 

> @title.squish
 => "abc"
> @title
 => " abc "

> @title.squish!
 => "abc"
> @title
 => "abc" 

หากคุณใช้เพียงทับทิมคุณต้องการใช้แถบ

ที่นี่ gotcha อยู่ .. ในกรณีของคุณที่คุณต้องการใช้แถบโดยไม่ต้องปัง!

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

แถบ! ใช้วิธีการหลายสาย

> tokens["Title"] = " abc "
 => " abc "
> tokens["Title"].strip!
 => "abc"
> @title = tokens["Title"]
 => "abc"

วิธีแถบบรรทัดเดียว ... คำตอบของคุณ

> tokens["Title"] = " abc "
 => " abc "
> @title = tokens["Title"].strip if tokens["Title"].present?
 => "abc"

4

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

@title = tokens[Title].strip! || tokens[Title] if tokens[Title]

ทางเลือกที่คุณสามารถใส่ไว้ในสองบรรทัด:

@title = tokens[Title] || ''
@title.strip!

3

หากคุณต้องการใช้วิธีอื่นหลังจากคุณต้องการสิ่งนี้:

( str.strip || str ).split(',')

วิธีนี้คุณสามารถดึงและยังคงทำอะไรต่อไป :)



1

หากคุณมี ruby ​​1.9 หรือ activesupport คุณสามารถทำได้ง่ายๆ

@title = tokens[Title].try :tap, &:strip!

นี่มันเจ๋งจริงๆเพราะมันใช้ประโยชน์จาก:tryและ:tapวิธีซึ่งเป็นโครงสร้างที่มีประสิทธิภาพมากที่สุดในทับทิมในความคิดของฉัน

รูปแบบที่น่ารักยิ่งขึ้นผ่านหน้าที่เป็นสัญลักษณ์โดยสิ้นเชิง:

@title = tokens[Title].send :try, :tap, &:strip!

-1
@title = tokens[Title].strip! || tokens[Title]

เป็นไปได้ทั้งหมดที่ฉันไม่เข้าใจหัวข้อ แต่จะไม่ทำสิ่งที่คุณต้องการ?

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