236

I am just wondering if there is any method to remove string from another string? Something like this:

class String
  def remove(s)
    self[s.length, self.length - s.length]
  end
end

9 Answers 9

293

You can use the slice method:

a = "foobar"
a.slice! "foo"
=> "foo"
a
=> "bar"

there is a non '!' version as well. More info can be seen in the documentation about other versions as well: http://www.ruby-doc.org/core/classes/String.html#method-i-slice-21

Sign up to request clarification or add additional context in comments.

11 Comments

Very elegant! You can also use []s for the non-bang version.
This has a bad side effect of returning the deleted text (or text searched for). Unfortunate for chaining on the result of the deletion.
How do you return the sliced string and not affect the original? For example if I have "hello world", I want to slice "hello " and return just the "world" part, without modifying the original string object?
@Mike "foobar".tap{|s| s.slice!("foo")}.upcase
@bcackerman -- delete wouldn't work, since it deletes all the characters you pass in: 'hello world'.delete('hello') #=> ' wrd'
|
192

How about str.gsub("subString", "") Check out the Ruby Doc

4 Comments

sub would be more appropriate than gsub, since the OP only wants to remove the substring from the beginning of the string, not all through the string (look at his sample code). And using a regex, like this, would be better: str.sub(/^subString/, '') -- because it ensures that the substring will definitely be removed only from the beginning.
@AlexD Using a regex would be better, but it's dangerous if we can't be sure subString doesn't include any regex special characters.
@DavidMoles, in this case, /^subString/ is a literal, so we can be very sure it doesn't include any metacharacters. If you are substituting some other string into a regex, you can do this: /#{Regexp.escape(str)}/.
In the answer, yes, but not in the OP's question. Thanks for the pointer to Regexp.escape(), though.
132

If it is a the end of the string, you can also use chomp:

"hello".chomp("llo")     #=> "he"

3 Comments

if the expression was a.chomp("llo"), chomp! is more precise.
This is cleaner than slice!, as this has no side effects.
If it is from the beginning of the string, you can also use chomp in combination with reverse: "hello".reverse.chomp("he".reverse).reverse #=> "llo"
65

Ruby 2.5+

If your substring is at the beginning of in the end of a string, then Ruby 2.5 has introduced the methods for this:

  • delete_prefix for removing a substring from the beginning of the string
  • delete_suffix for removing a substring from the end of the string

Comments

57

If you only have one occurrence of the target string you can use:

str[target] = ''

or

str.sub(target, '')

If you have multiple occurrences of target use:

str.gsub(target, '')

For instance:

asdf = 'foo bar'
asdf['bar'] = ''
asdf #=> "foo "

asdf = 'foo bar'
asdf.sub('bar', '') #=> "foo "
asdf = asdf + asdf #=> "foo barfoo bar"
asdf.gsub('bar', '') #=> "foo foo "

If you need to do in-place substitutions use the "!" versions of gsub! and sub!.

2 Comments

ruby is fun! really enjoy seeing stuff like: asdf['bar'] = ''
I wouldn't call that "fun" - non-intuitive, perhaps.
42

If you are using Rails there's also remove.

E.g. "Testmessage".remove("message") yields "Test".

Warning: this method removes all occurrences

3 Comments

This isn't a vanilla Ruby answer, but the accepted answer isn't quite what most people are looking for. Unfortunately the slice method doesn't return the portion of the string that's sliced, it returns the "knife"
@DylanPierce it's pretty easy to implement a function that does that using slice! def gimme_the_slice(my_string, my_slice) my_string.slice!(my_slice) my_string
Ah that's right, bang-ifying is how Ruby modifies the existing variable. Thanks @BennettTalpers
4

If you are using rails or at less activesupport you got String#remove and String#remove! method

def remove!(*patterns)
  patterns.each do |pattern|
    gsub! pattern, ""
  end

  self
end

source: http://api.rubyonrails.org/classes/String.html#method-i-remove

Comments

2

If I'm interpreting right, this question seems to ask for something like a minus (-) operation between strings, i.e. the opposite of the built-in plus (+) operation (concatenation).

Unlike the previous answers, I'm trying to define such an operation that must obey the property:

IF c = a + b THEN c - a = b AND c - b = a

We need only three built-in Ruby methods to achieve this:

'abracadabra'.partition('abra').values_at(0,2).join == 'cadabra'.

I won't explain how it works because it can be easily understood running one method at a time.

Here is a proof of concept code:

# minus_string.rb
class String
  def -(str)
    partition(str).values_at(0,2).join
  end
end

# Add the following code and issue 'ruby minus_string.rb' in the console to test
require 'minitest/autorun'

class MinusString_Test < MiniTest::Test

  A,B,C='abra','cadabra','abracadabra'

  def test_C_eq_A_plus_B
    assert C == A + B
  end

  def test_C_minus_A_eq_B
    assert C - A == B
  end

  def test_C_minus_B_eq_A
    assert C - B == A
  end

end

One last word of advice if you're using a recent Ruby version (>= 2.0): use Refinements instead of monkey-patching String like in the previous example.

It is as easy as:

module MinusString
  refine String do
    def -(str)
      partition(str).values_at(0,2).join
    end
  end
end

and add using MinusString before the blocks where you need it.

1 Comment

+1 for the concepts of refinements. While monkey-patching String class is probably an overkill for this use case, sometimes we do have to monkey-patch things and concept of refinements really shines at it.
-2

here's what I'd do

2.2.1 :015 > class String; def remove!(start_index, end_index) (end_index - start_index + 1).times{ self.slice! start_index }; self end; end;
2.2.1 :016 >   "idliketodeleteHEREallthewaytoHEREplease".remove! 14, 32
 => "idliketodeleteplease" 
2.2.1 :017 > ":)".remove! 1,1
 => ":" 
2.2.1 :018 > "ohnoe!".remove! 2,4
 => "oh!" 

Formatted on multiple lines:

class String
    def remove!(start_index, end_index)
        (end_index - start_index + 1).times{ self.slice! start_index }
        self
    end 
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.