231

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
Piyush Mattoo
  • 15,454
  • 6
  • 47
  • 56
ceth
  • 44,198
  • 62
  • 180
  • 289

9 Answers9

286

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

noraj
  • 3,964
  • 1
  • 30
  • 38
Pete
  • 17,885
  • 4
  • 32
  • 30
  • 1
    Very elegant! You can also use `[]`s for the non-bang version. – Matheus Moreira Mar 20 '11 at 07:57
  • 73
    This has a bad side effect of returning the deleted text (or text searched for). Unfortunate for chaining on the result of the deletion. – Mike Sep 02 '11 at 20:02
  • 10
    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? – jhabbott Oct 28 '11 at 15:50
  • 14
    @Mike `"foobar".tap{|s| s.slice!("foo")}.upcase` – Ernest Apr 04 '12 at 15:23
  • 1
    @jhabbott use `.delete()` for that – bcackerman Jan 18 '15 at 05:53
  • 8
    @bcackerman -- `delete` wouldn't work, since it deletes all the characters you pass in: `'hello world'.delete('hello') #=> ' wrd'` – rusty Jun 02 '15 at 14:55
  • @Mike Good call. I used `gsub`, which returns the original string, as @Piyush points out: http://stackoverflow.com/a/5367181/293280 – Joshua Pinter Aug 19 '15 at 00:36
  • This modifies the string in place, and therefore will fail with `can't modify frozen String` if you try to do it on a frozen string. Using `.gsub` instead works. – Jon Schneider Dec 06 '18 at 15:21
  • Just a heads up that the URL you have is broken. You can find the slice documentation at https://ruby-doc.org/core-2.6.3/String.html#method-i-slice. – disambiguator Jul 30 '19 at 20:14
  • slice! method will not modify the frozen strings, if you are using it inside the loop, in that case use remove. – vidur punj Oct 09 '19 at 06:53
  • In case someone else is wondering as well `a = "Hello Heman!"; a.slice! "He" ; puts a` will print `llo Heman!`, it will not remove the second `He`. – Daniel May 19 '22 at 11:17
188

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

Piyush Mattoo
  • 15,454
  • 6
  • 47
  • 56
  • 47
    `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. – Alex D Jan 17 '14 at 06:27
  • @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. – David Moles Aug 23 '16 at 22:55
  • @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)}/`. – Alex D Aug 24 '16 at 07:09
  • In the answer, yes, but not in the OP's question. Thanks for the pointer to `Regexp.escape()`, though. – David Moles Aug 24 '16 at 16:21
130

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

"hello".chomp("llo")     #=> "he"
Waiting for Dev...
  • 12,629
  • 5
  • 47
  • 57
62

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
Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
Igor Drozdov
  • 14,690
  • 5
  • 37
  • 53
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!.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
41

If you are using Rails there's also remove.

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

Warning: this method removes all occurrences

edwardmp
  • 6,339
  • 5
  • 50
  • 77
  • 1
    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" – Dylan Pierce Aug 07 '17 at 21:03
  • 1
    @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 ``` – Bennett Talpers Sep 29 '17 at 22:22
  • 1
    Ah that's right, bang-ifying is how Ruby modifies the existing variable. Thanks @BennettTalpers – Dylan Pierce Oct 02 '17 at 13:55
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

Dinatih
  • 2,456
  • 1
  • 21
  • 21
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.

Claudio Floreani
  • 2,441
  • 28
  • 34
  • 1
    +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. – wondersz1 May 27 '19 at 11:54
-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
JayTarka
  • 551
  • 5
  • 12