Idiom of removing a particular character from a String?

Hi all,

Is there any particular idiom for removing a particular character from a
string by index and returning the resulting string? The following
makes my old eyes sore:

rem = str.clone
rem[i] = “”
rem

as does this:

rem = str.scan(/./)
rem.delete_at(i)
rem.to_s

It seems there should be some more idiomatic way to do this, something
like str.annihilate_char_at_index_possibly_without_a_bang(i), read as
String#delete_at(i) and String#delete_at!(i). Of course these methods
don’t exist, and “”.methods doesn’t turn up anything interesting. So
what is a decent way of performing this?

Lorenzo

On Thu, Aug 14, 2008 at 11:21:10PM +0900, Lorenzo E. Danielsson wrote:

rem = str.scan(/./)
rem.delete_at(i)
rem.to_s

It seems there should be some more idiomatic way to do this, something
like str.annihilate_char_at_index_possibly_without_a_bang(i), read as
String#delete_at(i) and String#delete_at!(i). Of course these methods
don’t exist, and “”.methods doesn’t turn up anything interesting. So
what is a decent way of performing this?

str[index…index] = “”

Lorenzo
–Greg

On Thu, Aug 14, 2008 at 9:21 AM, Lorenzo E. Danielsson
[email protected] wrote:

as does this:

rem = str.scan(/./)
rem.delete_at(i)
rem.to_s

It seems there should be some more idiomatic way to do this, something
like str.annihilate_char_at_index_possibly_without_a_bang(i), read as
String#delete_at(i) and String#delete_at!(i). Of course these methods
don’t exist, and “”.methods doesn’t turn up anything interesting. So
what is a decent way of performing this?

irb(main):022:0> rem = “foobar”
=> “foobar”
irb(main):023:0> rem.slice!(3).chr
=> “b”
irb(main):024:0> rem
=> “fooar”

-Michael

On Thu, 2008-08-14 at 23:40 +0900, Gregory S. wrote:

str[index…index] = “”
So:
str = “hello”
rem = str.clone
rem[2,1] = “” # => “helo”
rem

Sorry, but that doesn’t look any cleaner than my solution. I was looking
for something like:

class String
def delete_at(i)
str = self.clone
str[i] = “”
end
end

str = “hello”
rem = str.delete_at(2) # => “helo”

That is, original string does not get tampered with. Resulting string is
original string minus exactly one character, at the specified index.

The above works, but I was hoping to avoid that by using some neat
idiom. This is not really a problem, but 99.x % of the time, Ruby does
things in a way that are so cool that I tend to get lazy and expect it
to always behave that way. The few times it doesn’t, it comes as a
shock.

On Thu, 2008-08-14 at 23:52 +0900, Michael L. wrote:

rem
don’t exist, and “”.methods doesn’t turn up anything interesting. So
what is a decent way of performing this?

irb(main):022:0> rem = “foobar”
=> “foobar”
irb(main):023:0> rem.slice!(3).chr
=> “b”
irb(main):024:0> rem
=> “fooar”

The “problem” is that slice does not return the resulting string but
rather the sliced portion. This is of course not a problem in itself, it
is rather the expected behavior of slice. But, in my particular case
that still leads to:

str = “hello”
rem = str.clone
rem.slice!(2)
rem # => “helo”

Whereas I would have wanted:

str = “hello”
rem = str.slice_and_return_everything_but_the_sliced_part(2)

This is partly a matter of laziness on my part, that I prefer to type
two lines instead of four. But, it is also a matter that it kind of
breaks the POLS, at least for me. I have grown accustomed to being able
to perform:

result = original.some_method(args)

and have the result be some mutilated form of original, with original
being left intact. So when String#delete_at(index) doesn’t work, it
feels like it should have worked…

Anyways, nothing worth losing sleep over…

On Aug 14, 2008, at 8:21 AM, Lorenzo E. Danielsson wrote:

what is a decent way of performing this?

Lorenzo

don’t do it by index

string.tr! chars, ‘’

a @ http://codeforpeople.com/

On Thursday 14 August 2008 11:59:51 Lorenzo E. Danielsson wrote:

So:
str = “hello”
rem = str.clone
rem[2,1] = “” # => “helo”
rem

For what it’s worth, I’ve been using Object#tap (1.8.7 or higher) in
situations like these:

str = “hello”
str.clone.tap { |rem|
rem[2,1] = ‘’
}

Ordinarily, I wouldn’t mention it, but you were asking for idiomatic
things,
and I like that idiom.

On Aug 14, 9:21 am, “Lorenzo E. Danielsson”
[email protected] wrote:

as does this:

Lorenzo

Lorenzo,

It seems reading comprehension isn’t a strong suit for ruby-talk
today.

As far as I know, there is no such method. You’re probably stuck with
reopening String and adding it yourself.

On Fri, 2008-08-15 at 11:56 +0900, David M. wrote:

str = “hello”
str.clone.tap { |rem|
rem[2,1] = ‘’
}

Ordinarily, I wouldn’t mention it, but you were asking for idiomatic things,
and I like that idiom.

Agreed, Object#tap looks very nice. Thanks for the info.

Lorenzo

2008/8/14 Lorenzo E. Danielsson [email protected]:

On Thu, 2008-08-14 at 23:52 +0900, Michael L. wrote:

On Thu, Aug 14, 2008 at 9:21 AM, Lorenzo E. Danielsson

Whereas I would have wanted:

and have the result be some mutilated form of original, with original
being left intact. So when String#delete_at(index) doesn’t work, it
feels like it should have worked…

Anyways, nothing worth losing sleep over…

If you want to do it on one line you could do this:

irb(main):011:0> s = “abcdef”
=> “abcdef”
irb(main):012:0> 5.times {|i| puts s.sub /\A(.{#{i}})./, ‘\1’ }
bcdef
acdef
abdef
abcef
abcdf
=> 5
irb(main):013:0>

Granted, it’s not too idiomatic…

Kind regards

robert

Lorenzo E. Danielsson wrote:

Hi all,

Is there any particular idiom for removing a particular character from a
string by index and returning the resulting string?

str[0…index]+str[index+1…-1]

NB: this won’t delete the char from str but only return a new string
without the character at index.

regards
Stefan R. (“apeiros”)

Lorenzo E. Danielsson wrote:

as does this:

Lorenzo

There have been some good solutions posted already. However, I don’t
think I’d want to be repeating them many times (or at all) in my code.
Whichever solution you use, it’s probably best to hide it away in the
String class somewhere, else your code will suddenly start looking…
perl-like.

This seems sensible to me. If you’re on 1.8.7 or 1.9 (I am not), you
can also use the tap method.

class String
def rem(idx)
c = clone
c[idx…idx] = “”
c
end

def rem!(idx)
self[idx…idx] = “”
self
end
end

If you’re on 1.8.7, 1.9 or feel like implementing it yourself, you can
use the tap method. Using the tap method seems cleaner.

unless Object.methods.include? “tap”
class Object
def tap
yield self
self
end
end
end

class String
def rem(idx)
clone.tap {|t| t[idx…idx] = “” }
end

def rem!(idx)
tap {|t| t[idx…idx] = “” }
end
end