What is the canonical way to trim a string in Ruby without creating a new string?

Go To StackoverFlow.com

170

This is what I have now - which looks too verbose for the work it is doing.

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

Assume tokens is a array obtained by splitting a CSV line. now the functions like strip! chomp! et. all return nil if the string was not modified

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

What is the Ruby way to say trim it if it contains extra leading or trailing spaces without creating copies?

Gets uglier if I want to do tokens[Title].chomp!.strip!

2009-06-16 10:30
by Gishu
If you're going to be reading things out of tokens repeatedly, it might make more sense to pre-process it. I.e., " tokens.each {|t| t.strip!} ". then you can just do " @title = tokens[Title] || '' - glenn mcdonald 2009-06-16 18:38


248

I guess what you want is:

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

The #strip! method will return nil if it didn't strip anything, and the variable itself if it was stripped.

According to Ruby standards, a method suffixed with an exclamation mark changes the variable in place.

Hope this helps.

Update: This is output from irb to demonstrate:

>> @title = "abc"
=> "abc"
>> @title.strip!
=> nil
>> @title
=> "abc"
>> @title = " abc "
=> " abc "
>> @title.strip!
=> "abc"
>> @title
=> "abc"
2009-06-16 11:29
by Igor
Hmm.. still I think @title = tokens[Title].strip! looks cleaner - its a pity it returns nil instead of the unmodified string. Unless someone posts a better ans.. you're getting the accepted bit - Gishu 2009-06-16 12:00
Well, @title = tokens[Title].strip will do the trick but you'd have a copy instead, which is fine if you keep the tokens[Title] variable untouched - Igor 2009-06-16 12:32
If you want a method to return the unmodified string, you could easily make your own: def stripreturningself() strip! || self en - Chuck 2009-06-16 19:49
@chuck Yeah. but I was hoping there was a neat trick to do that without rolling my own method - Gishu 2009-06-17 04:16
Ruby 1.9 has tap, which does exactly what you want: @title.tap{|x| x.strip! - timkay 2011-06-06 15:23
@timkay Would it be possible to do @title.tap &:strip!? That seems cleaner than anything else - Jon Egeland 2013-07-19 14:38
Why in the world would it return nil unless it strips something? That has no doubt confused a ton of people (since it makes no sense) - Josh M. 2014-01-27 02:08
@JoeAtzberger Any idea which version of Ruby this bogusness is removed in - Joshua Pinter 2015-07-03 11:52
@JoshPinter deleted my comment that newer versions addressed this, since I could not verify on ruby 2.1.2 or 2.2.0 - Joe Atzberger 2015-07-04 18:49
@JoeAtzberger Thanks for following-up. Couldn't find it either so wanted to double check. Surprised it's still in there, to be honest - Joshua Pinter 2015-07-05 18:12
Sorry for resurrecting such an old discussion... But how is @title.tap &:strip! clearer/cleaner than @title.strip! - Davi Koscianski Vidal 2018-09-18 12:10


48

Btw, now ruby already supports just strip without "!".

Compare:

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

Also it's impossible to strip without duplicates. See sources in 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]

Update 1: As I see now -- it was created in 1999 year (see rev #372 in SVN):

Update2: strip! will not create duplicates — both in 1.9.x, 2.x and trunk versions.

2012-04-08 10:46
by gaRex
"it's impossible to stripping without duplicates" - of course it's possible, that's what strip! is for - Karoly Horvath 2015-10-27 22:04
@KarolyHorvath dont' you see the source code, written in C? Pls read carefully, what I written here regarding duplicates - gaRex 2015-10-29 09:14
Of course i see it. But that's the source code of strip. Am I misunderstand something? How else could I interpret "impossible to stripping without duplicate" - Karoly Horvath 2015-10-29 13:11
@KarolyHorvath internally duplicate is always created. That's about string str = rb_str_dup(str);gaRex 2015-10-29 13:19
And if you don't want a duplicate, you use strip! aka rb_str_strip_bang - Karoly Horvath 2015-10-29 13:25
@KarolyHorvath I see now, what do you mean. I've used bad term "stripping". I mean there only "strip" and not "strip!". So I added note about bang-version - gaRex 2015-10-29 13:52


8

There's no need to both strip and chomp as strip will also remove trailing carriage returns - unless you've changed the default record separator and that's what you're chomping.

Olly's answer already has the canonical way of doing this in Ruby, though if you find yourself doing this a lot you could always define a method for it:

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

Giving:

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

Also keep in mind that the if statement will prevent @title from being assigned if the token is nil, which will result in it keeping its previous value. If you want or don't mind @title always being assigned you can move the check into the method and further reduce duplication:

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

As an alternative, if you're feeling adventurous you can define a method on String itself:

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

Giving one of:

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

@title = tokens[Title] && tokens[Title].strip_or_self!
2009-06-16 11:44
by NoName
Although not technically the answer. Thanks.. didn't know that. - Gishu 2009-06-16 11:58


7

If you are using Ruby on Rails there is a squish

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

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

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

If you are using just Ruby you want to use strip

Herein lies the gotcha.. in your case you want to use strip without the bang !

while strip! certainly does return nil if there was no action it still updates the variable so strip! cannot be used inline. If you want to use strip inline you can use the version without the bang !

strip! using multi line approach

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

strip single line approach... YOUR ANSWER

> tokens["Title"] = " abc "
 => " abc "
> @title = tokens["Title"].strip if tokens["Title"].present?
 => "abc"
2015-10-27 21:56
by gateblues


2

I think your example is a sensible approach, although you could simplify it slightly as:

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

Alternative you could put it on two lines:

@title = tokens[Title] || ''
@title.strip!
2009-06-16 11:33
by Olly


2

If you want to use another method after you need something like this:

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

This way you can strip and still do something after :)

2015-12-01 12:18
by Diogo Neves - Mangaru


1

My way:

> (@title = " abc ").strip!
 => "abc" 
> @title
 => "abc" 
2012-04-08 10:51
by Hauleth


1

If you have either ruby 1.9 or activesupport, you can do simply

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

This is really cool, as it leverages the :try and the :tap method, which are the most powerful functional constructs in ruby, in my opinion.

An even cuter form, passing functions as symbols altogether:

@title = tokens[Title].send :try, :tap, &:strip!
2013-11-15 20:39
by rewritten


-1

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

It's entirely possible i'm not understanding the topic, but wouldn't this do what you need?

" success ".strip! || "rescue" #=> "success"
"failure".strip! || "rescue" #=> "rescue"
2013-10-30 04:48
by Brent
Ads