Ruby, loại bỏ N ký tự cuối cùng khỏi một chuỗi?


263

Cách ưa thích để loại bỏ các nký tự cuối cùng khỏi một chuỗi là gì?


Nếu bạn biết hậu tố (câu trả lời hàng đầu cho thấy rất nhiều người đến đây tìm kiếm điều này), bạn có thể sử dụng delete_suffixtừ Ruby 2.5. Thêm thông tin ở đây .
SRack

Câu trả lời:


36

Ruby 2.5+

Kể từ Ruby 2.5, bạn có thể sử dụng delete_suffixhoặc delete_suffix!để đạt được điều này một cách nhanh chóng và dễ đọc.

Các tài liệu về các phương pháp là ở đây .

Nếu bạn biết hậu tố là gì, thì đây là thành ngữ (và tôi tranh luận, thậm chí còn dễ đọc hơn các câu trả lời khác ở đây):

'abc123'.delete_suffix('123')     # => "abc"
'abc123'.delete_suffix!('123')    # => "abc"

Nó thậm chí còn nhanh hơn đáng kể (gần 40% với phương pháp bang) so với câu trả lời hàng đầu. Đây là kết quả của cùng một điểm chuẩn:

                     user     system      total        real
chomp            0.949823   0.001025   0.950848 (  0.951941)
range            1.874237   0.001472   1.875709 (  1.876820)
delete_suffix    0.721699   0.000945   0.722644 (  0.723410)
delete_suffix!   0.650042   0.000714   0.650756 (  0.651332)

Tôi hy vọng điều này hữu ích - lưu ý rằng phương thức hiện không chấp nhận regex vì vậy nếu bạn không biết hậu tố thì hiện tại nó không khả thi. Tuy nhiên, vì câu trả lời được chấp nhận ( cập nhật: tại thời điểm viết ) cũng giống như vậy, tôi nghĩ rằng điều này có thể hữu ích với một số người.


1
@JPSilvashy Tôi chưa bao giờ hài lòng hơn khi mất dấu. Đây là một câu trả lời tuyệt vời.
Wayne Conrad

1
Đây là một chức năng tuyệt vời và nhanh chóng, nhưng đây không phải là câu trả lời đúng bởi vì nó không trả lời chính xác câu hỏiWhat is the preferred way of removing the last n characters from a string?
Sam

1
Cảm ơn phản hồi @Sam - câu hỏi này đã có câu trả lời trong gần chín năm hoạt động giống như câu hỏi này, với 261 lượt upvote tại thời điểm viết. JP đã chấp nhận điều đó và gần đây đã chuyển sang vấn đề này, vì vậy tôi nói rằng nó đã trả lời câu hỏi của họ :) Tôi nghĩ rằng tôi đã đưa nó vào như một giải pháp thay thế hiện đại và hy vọng nó sẽ giúp những người hạ cánh ở đây. Trên thực tế, tôi đã đề cập đến tất cả những điều này trong câu hỏi - Tôi hy vọng phương pháp này sớm chấp nhận một biểu thức chính quy, mặc dù có một sự thay thế hoàn hảo cho trường hợp của bạn ngay dưới đây.
SRack

316
irb> 'now is the time'[0...-4]
=> "now is the "

9
Lưu ý rằng điều này chỉ hoạt động trong Ruby 1.9. Trong Ruby 1.8, điều này sẽ loại bỏ các byte cuối cùng , không phải các ký tự cuối cùng .
Jörg W Mittag

2
Nhưng anh ta có lẽ có nghĩa là "byte" nếu anh ta đang sử dụng 1.8.x.
DigitalRoss

4
Điều này không hoạt động, nhưng tôi đang tìm thấy 'abc123'.chomp (' 123 ') để nhanh gấp đôi cho cả chuỗi ngắn và rất dài. (Ruby 2.0.0-p247) Có ai có thể xác nhận điều này không?
Plasmarob

10
Đối với những người thắc mắc tại sao ví dụ cụ thể này không hoạt động..có 3 chấm chứ không phải 2 tức là [0...-4]không[0..-4]
rorofromfrance 2/12/13

2
@Plamarob Tôi nghĩ rằng có liên quan hơn khi nói rằng chomp nhanh hơn 53 nano giây so với việc nói rằng nó nhanh gấp đôi. Sau đó, bạn có thể ước tính tốt hơn chi phí so với giá trị của việc sử dụng nó và liệu nó có thể là điều cần tối ưu hóa trong một tình huống nhất định.
Caesoid

266

Nếu các ký tự bạn muốn xóa luôn là các ký tự giống nhau, thì hãy xem xét chomp:

'abc123'.chomp('123')    # => "abc"

Ưu điểm của chomplà: không đếm và mã thông báo rõ hơn những gì nó đang làm.

Không có đối số, chomploại bỏ kết thúc dòng DOS hoặc Unix, nếu có mặt:

"abc\n".chomp      # => "abc"
"abc\r\n".chomp    # => "abc"

Từ các ý kiến, đã có một câu hỏi về tốc độ sử dụng #chompso với sử dụng một phạm vi. Đây là một điểm chuẩn so sánh hai:

require 'benchmark'

S = 'asdfghjkl'
SL = S.length
T = 10_000
A = 1_000.times.map { |n| "#{n}#{S}" }

GC.disable

Benchmark.bmbm do |x|
  x.report('chomp') { T.times { A.each { |s| s.chomp(S) } } }
  x.report('range') { T.times { A.each { |s| s[0...-SL] } } }
end

Kết quả điểm chuẩn (sử dụng CRuby 2.13p242):

Rehearsal -----------------------------------------
chomp   1.540000   0.040000   1.580000 (  1.587908)
range   1.810000   0.200000   2.010000 (  2.011846)
-------------------------------- total: 3.590000sec

            user     system      total        real
chomp   1.550000   0.070000   1.620000 (  1.610362)
range   1.970000   0.170000   2.140000 (  2.146682)

Vì vậy, chomp nhanh hơn so với sử dụng một phạm vi, bằng ~ 22%.


5
Chop cũng là một lựa chọn. Nó ít cầu kỳ hơn về những gì được gỡ bỏ.
Andrew Grimm

1
Tôi thấy điều ngược lại là thực sự đúng. Thực tế là .chomp dường như liên tục nhanh gấp đôi.
Plasmarob

3
@Plamarob, Điểm chuẩn trong Ruby thường gây ngạc nhiên. Tôi thường sai đến nỗi tôi không còn cố đoán xem cái gì sẽ nhanh hơn. Ngoài ra, nếu câu trả lời sẽ được cải thiện bởi kết quả điểm chuẩn, xin vui lòng chỉnh sửa nó.
Wayne Conrad

1
Nếu tôi đọc đúng mã, phạm vi sẽ mất khoảng 53 nano giây so với chomp. Nó có thể là một lực cản đáng kể trong một số trường hợp nhất định, nhưng giữ tốc độ tuyệt đối trong tâm trí (chứ không chỉ là người thân) có thể cho bạn biết liệu bạn có nên đi qua cơ sở mã của mình và thay đổi tất cả các phạm vi của bạn thành chomps (nếu có). Chắc là không.
Caesoid

1
Công trình tuyệt vời. Và bạn có thể sử dụng chomp!()để hành động trên Chuỗi tại chỗ.
Joshua Pinter

57
str = str[0...-n]

5
Lưu ý rằng điều này chỉ hoạt động trong Ruby 1.9. Trong Ruby 1.8, điều này sẽ loại bỏ các byte cuối cùng , không phải các ký tự cuối cùng .
Jörg W Mittag

5
Điều này tốt hơn câu trả lời đã chọn, vì 3 dấu chấm (...) dễ ghi nhớ hơn vì -n có nghĩa là lấy ra n ký tự từ cuối chuỗi.
lulalala

cũng "abcd" [0 ..- 2] # => "abc" trong khi "abcd" [0 ...- 2] # => "ab". Theo tôi, tùy chọn phạm vi 3 chấm dẫn đến một mã tự giải thích nhiều hơn.
mokagio

31

Tôi sẽ đề nghị chop. Tôi nghĩ rằng nó đã được đề cập trong một trong những bình luận nhưng không có liên kết hoặc giải thích vì vậy đây là lý do tại sao tôi nghĩ nó tốt hơn:

Nó chỉ đơn giản là xóa ký tự cuối cùng khỏi một chuỗi và bạn không phải chỉ định bất kỳ giá trị nào cho điều đó xảy ra.

Nếu bạn cần loại bỏ nhiều hơn một ký tự thì đó chomplà đặt cược tốt nhất của bạn. Đây là những gì các tài liệu ruby phải nói về chop:

Trả về một Chuỗi mới với ký tự cuối cùng bị xóa. Nếu chuỗi kết thúc bằng \ r \ n, cả hai ký tự sẽ bị xóa. Áp dụng chop vào một chuỗi rỗng trả về một chuỗi rỗng. Chuỗi # chomp thường là một sự thay thế an toàn hơn, vì nó không thay đổi chuỗi nếu nó không kết thúc bằng dấu tách.

Mặc dù điều này được sử dụng chủ yếu để xóa các dấu phân cách như \r\ntôi đã sử dụng nó để xóa ký tự cuối cùng khỏi một chuỗi đơn giản, ví dụ: sđể tạo từ số ít.


1
Không phải chỉ cần loại bỏ ký tự cuối cùng đó sao? Câu hỏi là về "các ký tự" ở số nhiều
maetthew

1
Đúng, bạn đúng, nhưng chomp ('chars') sẽ xóa 'chars' cuối cùng. Tôi không rõ nếu OP muốn các ký tự cụ thể hay chỉ N ký tự.
kakubei

Vâng, đây là câu trả lời, chỉ khi bạn muốn xóa chỉ một ký tự (đó là trường hợp với tôi).
Quv

29
name = "my text"
x.times do name.chop! end

Ở đây trong bảng điều khiển:

>name = "Nabucodonosor"
 => "Nabucodonosor" 
> 7.times do name.chop! end
 => 7 
> name
 => "Nabuco" 

Đây có phải là hiệu quả? Có vẻ đáng so sánh với các câu trả lời khác :)
SRack

16

Bỏ các nký tự cuối cùng cũng giống như giữ các length - nký tự đầu tiên .

Hỗ trợ tích cực bao gồm String#firstString#lastcác phương thức cung cấp một cách thuận tiện để giữ hoặc xóa các nký tự đầu tiên / cuối cùng :

require 'active_support/core_ext/string/access'

"foobarbaz".first(3)  # => "foo"
"foobarbaz".first(-3) # => "foobar"
"foobarbaz".last(3)   # => "baz"
"foobarbaz".last(-3)  # => "barbaz"

7

nếu bạn đang sử dụng đường ray, hãy thử:

"my_string".last(2) # => "ng"

[EDITED]

Để có được chuỗi KHÔNG CÓ 2 ký tự cuối cùng:

n = "my_string".size
"my_string"[0..n-3] # => "my_stri"

Lưu ý: char chuỗi cuối cùng là ở n-1. Vì vậy, để loại bỏ 2 cuối cùng, chúng tôi sử dụng n-3.


2
Điều này không loại bỏ hai chữ cái cuối cùng. Nó trả lại cho họ.
JP Silvashy

1
Trước tiên, bạn không cần phải đo chuỗi, ruby ​​sử dụng các chỉ số âm từ cuối chuỗi nguyên bản
Devon Parsons

3

Bạn luôn có thể sử dụng một cái gì đó như

 "string".sub!(/.{X}$/,'')

Trong trường hợp Xlà số ký tự để loại bỏ.

Hoặc với việc gán / sử dụng kết quả:

myvar = "string"[0..-X]

trong đó Xsố lượng ký tự cộng với một ký tự để loại bỏ.



1

Nếu bạn ổn với việc tạo các phương thức lớp và muốn các ký tự bạn cắt ra, hãy thử điều này:

class String
  def chop_multiple(amount)
    amount.times.inject([self, '']){ |(s, r)| [s.chop, r.prepend(s[-1])] }
  end
end

hello, world = "hello world".chop_multiple 5
hello #=> 'hello '
world #=> 'world'

0

Sử dụng regex:

str = 'string'
n = 2  #to remove last n characters

str[/\A.{#{str.size-n}}/] #=> "stri"

0

Nếu các ký tự bạn muốn xóa luôn là các ký tự giống nhau, thì hãy xem xét chomp:

'abc123'. chomp ('123')


-3
x = "my_test"
last_char = x.split('').last

3
câu hỏi là về việc loại bỏ N ký tự cuối cùng khỏi một chuỗi, không phải về việc tìm kiếm ký tự cuối cùng
unitallman
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.