[ruby] Ruby, remove last N characters from a string?

What is the preferred way of removing the last n characters from a string?

This question is related to ruby string

The answer is


If you're ok with creating class methods and want the characters you chop off, try this:

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'

Dropping the last n characters is the same as keeping the first length - n characters.

Active Support includes String#first and String#last methods which provide a convenient way to keep or drop the first/last n characters:

require 'active_support/core_ext/string/access'

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

You can always use something like

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

Where X is the number of characters to remove.

Or with assigning/using the result:

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

where X is the number of characters plus one to remove.


if you are using rails, try:

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

[EDITED]

To get the string WITHOUT the last 2 chars:

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

Note: the last string char is at n-1. So, to remove the last 2, we use n-3.


str = str[0...-n]

I would suggest chop. I think it has been mentioned in one of the comments but without links or explanations so here's why I think it's better:

It simply removes the last character from a string and you don't have to specify any values for that to happen.

If you need to remove more than one character then chomp is your best bet. This is what the ruby docs have to say about chop:

Returns a new String with the last character removed. If the string ends with \r\n, both characters are removed. Applying chop to an empty string returns an empty string. String#chomp is often a safer alternative, as it leaves the string unchanged if it doesn’t end in a record separator.

Although this is used mostly to remove separators such as \r\n I've used it to remove the last character from a simple string, for example the s to make the word singular.


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

Using regex:

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

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

If the characters you want to remove are always the same characters, then consider chomp:

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

The advantages of chomp are: no counting, and the code more clearly communicates what it is doing.

With no arguments, chomp removes the DOS or Unix line ending, if either is present:

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

From the comments, there was a question of the speed of using #chomp versus using a range. Here is a benchmark comparing the two:

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

Benchmark Results (using 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)

So chomp is faster than using a range, by ~22%.


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

Here in the console:

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

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