Cách chính tắc để cắt một chuỗi trong Ruby mà không tạo ra một chuỗi mới là gì?


182

Đây là những gì tôi có bây giờ - có vẻ quá dài dòng cho công việc nó đang làm.

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

Giả sử mã thông báo là một mảng thu được bằng cách tách một dòng CSV. Bây giờ các chức năng như dải! nhai! et. tất cả trả về nil nếu chuỗi không được sửa đổi

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

Cách Ruby để nói cắt nó là gì nếu nó chứa thêm khoảng trắng hàng đầu hoặc dấu mà không tạo bản sao?

Trở nên xấu hơn nếu tôi muốn làm tokens[Title].chomp!.strip!


3
Nếu bạn sẽ đọc những thứ ngoài mã thông báo nhiều lần, có thể có ý nghĩa hơn để xử lý trước nó. Tức là, "tokens.each {| t | t.strip!}". sau đó bạn chỉ có thể thực hiện "@title = tokens [Tiêu đề] || ''"
glenn mcdonald

Câu trả lời:


272

Tôi đoán những gì bạn muốn là:

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

Các #strip!phương pháp sẽ trở lạinil nếu nó không lột bất cứ điều gì, và biến chính nó nếu nó được lột.

Theo tiêu chuẩn của Ruby, một phương thức được thêm vào dấu chấm than làm thay đổi biến tại chỗ.

Hi vọng điêu nay co ich.

Cập nhật: Đây là đầu ra từ irbđể chứng minh:

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

1
Hmm .. tôi vẫn nghĩ @title = tokens [Tiêu đề] .strip! trông sạch hơn - thật đáng tiếc, nó trả về nil thay vì chuỗi không thay đổi. Trừ khi ai đó đăng một ans tốt hơn .. bạn sẽ nhận được bit được chấp nhận.
Gishu

7
Chà, @title = mã thông báo [Tiêu đề] .strip sẽ thực hiện thủ thuật nhưng thay vào đó bạn sẽ có một bản sao, điều này sẽ ổn nếu bạn giữ biến số mã thông báo [Tiêu đề] không bị ảnh hưởng.
Igor

9
Ruby 1.9 có vòi, thực hiện chính xác những gì bạn muốn: @ title.tap {| x | x.strip!}
timkay

2
@timkay Có thể làm được @title.tap &:strip!không? Điều đó dường như sạch hơn bất cứ điều gì khác.
Jon Egeland

16
Tại sao trên thế giới nó sẽ trở lại niltrừ khi nó tước đi thứ gì đó? Điều đó không có nghi ngờ nhầm lẫn một tấn người (vì nó không có ý nghĩa).
Josh M.

53

Btw, bây giờ ruby ​​đã hỗ trợ chỉ dải mà không có "!".

Đối chiếu:

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

Ngoài ra, không thể stripkhông có bản sao. Xem các nguồn trong chuỗi.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]

Cập nhật 1: Như tôi thấy bây giờ - nó được tạo ra vào năm 1999 (xem rev # 372 trong SVN):

Update2: strip!sẽ không tạo các bản sao - cả phiên bản 1.9.x, 2.x và trunk.


1
"Không thể tước bỏ mà không trùng lặp" - tất nhiên là có thể, đó là những gì strip!dành cho.
Karoly Horvath

@KarolyHorvath không 'bạn thấy mã nguồn, được viết bằng C? Xin đọc kỹ, những gì tôi viết ở đây liên quan đến các bản sao.
gaRex

1
Tất nhiên tôi thấy nó. Nhưng đó là mã nguồn của strip. Tôi có hiểu lầm gì không? Làm thế nào khác tôi có thể giải thích "không thể tước mà không trùng lặp"?
Karoly Horvath

@KarolyHorvath trùng lặp nội bộ luôn được tạo. Đó là về chuỗi `str = rb_str_dup (str);`
gaRex

1
Và nếu bạn không muốn một bản sao, bạn sử dụng strip!aka rb_str_strip_bang.
Karoly Horvath

9

Không cần cả dải và chomp vì dải cũng sẽ loại bỏ trả về vận chuyển kéo - trừ khi bạn đã thay đổi dấu tách bản ghi mặc định và đó là những gì bạn đang nhai.

Câu trả lời của Olly đã có cách thức kinh điển trong Ruby, mặc dù nếu bạn thấy mình làm điều này rất nhiều, bạn luôn có thể định nghĩa một phương thức cho nó:

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

Tặng:

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

Ngoài ra, hãy nhớ rằng câu lệnh if sẽ ngăn không @titleđược gán nếu mã thông báo không, điều này sẽ dẫn đến việc nó giữ giá trị trước đó. Nếu bạn muốn hoặc không bận tâm @titleluôn được chỉ định, bạn có thể chuyển séc vào phương thức và tiếp tục giảm trùng lặp:

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

Thay vào đó, nếu bạn cảm thấy thích phiêu lưu, bạn có thể định nghĩa một phương thức trên chính Chuỗi:

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

Đưa ra một trong:

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

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

9

Nếu bạn đang sử dụng Ruby on Rails, có một squish

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

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

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

Nếu bạn đang sử dụng chỉ Ruby, bạn muốn sử dụng dải

Đây là gotcha .. trong trường hợp của bạn, bạn muốn sử dụng dải mà không có tiếng nổ!

Trong khi dải! chắc chắn không trả về nil nếu không có hành động nó vẫn cập nhật biến nên thoát! không thể được sử dụng nội tuyến. Nếu bạn muốn sử dụng dải nội tuyến, bạn có thể sử dụng phiên bản mà không cần tiếng nổ!

dải! sử dụng phương pháp đa dòng

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

dải tiếp cận đường đơn ... TRẢ LỜI CỦA BẠN

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

4

Tôi nghĩ rằng ví dụ của bạn là một cách tiếp cận hợp lý, mặc dù bạn có thể đơn giản hóa nó một chút như:

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

Thay thế bạn có thể đặt nó trên hai dòng:

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

3

Nếu bạn muốn sử dụng một phương pháp khác sau khi bạn cần một cái gì đó như thế này:

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

Bằng cách này bạn có thể thoát y và vẫn làm một cái gì đó sau :)


1

Cách của tôi

> (@title = " abc ").strip!
 => "abc" 
> @title
 => "abc" 

1

Nếu bạn có ruby ​​1.9 hoặc hỗ trợ kích hoạt, bạn có thể làm đơn giản

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

Điều này thực sự tuyệt vời, vì nó thúc đẩy :try:tapphương pháp, đó là các cấu trúc chức năng mạnh nhất trong ruby, theo ý kiến ​​của tôi.

Một dạng chẵn, chuyển các chức năng như các biểu tượng hoàn toàn:

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

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

Hoàn toàn có thể tôi không hiểu chủ đề này, nhưng điều này sẽ không làm những gì bạn cần chứ?

" success ".strip! || "rescue" #=> "success"
"failure".strip! || "rescue" #=> "rescue"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.