String substitution without RegEx

I wanted to do a simple string substitution, and was surprised to see
that there isn’t such a method in ruby. I can’t use String::(g)sub,
because the substitution mustn’t be influenced by special chars or
backreferences in the pattern and replacement strings. Of course I could
write functions to escape regex special chars in the pattern and
backreferences in the replacement string, but this is about the ugliest
solution I can think of.

Andreas

···


AVR-Tutorial, über 350 Links
Forum für AVRGCC und MSPGCC
-> http://www.mikrocontroller.net

I wanted to do a simple string substitution, and was surprised to see
that there isn't such a method in ruby. I can't use String::(g)sub,
because the substitution mustn't be influenced by special chars or
backreferences in the pattern and replacement strings. Of course I could
write functions to escape regex special chars in the pattern and
backreferences in the replacement string, but this is about the ugliest
solution I can think of.

Well Regexp#escape don't do what you want ?

svg% ri Regexp#escape
--------------------------------------------------------- Regexp::escape
     Regexp.escape( aString ) -> aNewString

···

------------------------------------------------------------------------
     Escapes any characters that would have special meaning in a regular
     expression. For any string, Regexp.escape(str)=~str will be true.
        Regexp.escape('\\*?{}.') #=> \\\\\*\?\{\}\.

svg%

Guy Decoux

In article slrnbhr0jv.d34.usenet@home.andreas-s.net,

···

Andreas Schwarz usenet@andreas-s.net wrote:

I wanted to do a simple string substitution, and was surprised to see
that there isn’t such a method in ruby. I can’t use String::(g)sub,
because the substitution mustn’t be influenced by special chars or
backreferences in the pattern and replacement strings. Of course I could
write functions to escape regex special chars in the pattern and
backreferences in the replacement string, but this is about the ugliest
solution I can think of.

You can use Regexp.escape rather than write one yourself.

[mike@ratdog mike]$ ri Regexp::escape
This is a test ‘ri’. Please report errors and omissions
on http://www.rubygarden.org/ruby?RIOnePointEight

--------------------------------------------------------- Regexp::escape
Regexp.escape( aString ) → aNewString

  Escapes any characters that would have special meaning in a regular
  expression. For any string, Regexp.escape(str)=~str will
  be true.
          Regexp.escape('\\*?{}.')   #=> \\\\\*\?\{\}\.

e.g.

[mike@ratdog mike]$ irb --simple-prompt

s = ‘Oh $.?!’
=> "Oh $
.?!"
s.gsub(/#{Regexp.escape(’$*.?')}/, ‘dear’)
=> “Oh dear!”

Hope this helps,

Mike


mike@stok.co.uk | The “`Stok’ disclaimers” apply.
http://www.stok.co.uk/~mike/ | GPG PGP Key 1024D/059913DA
mike@exegenix.com | Fingerprint 0570 71CD 6790 7C28 3D60
http://www.exegenix.com/ | 75D2 9EC4 C1C0 0599 13DA

Andreas Schwarz wrote:

I wanted to do a simple string substitution, and was surprised to see
that there isn’t such a method in ruby. I can’t use String::(g)sub,
because the substitution mustn’t be influenced by special chars or
backreferences in the pattern and replacement strings. Of course I could
write functions to escape regex special chars in the pattern and
backreferences in the replacement string, but this is about the ugliest
solution I can think of.

There’s a subliminate message here…

irb(main):006:0> a = “dave”
=> “dave”
irb(main):007:0> a[“av”] = “onat”
=> “onat”
irb(main):008:0> a
=> “donate”

“Andreas Schwarz” usenet@andreas-s.net schrieb im Newsbeitrag
news:slrnbhr0jv.d34.usenet@home.andreas-s.net

I wanted to do a simple string substitution, and was surprised to see
that there isn’t such a method in ruby. I can’t use String::(g)sub,
because the substitution mustn’t be influenced by special chars or
backreferences in the pattern and replacement strings. Of course I could
write functions to escape regex special chars in the pattern and
backreferences in the replacement string, but this is about the ugliest
solution I can think of.

Where’s the problem?

irb(main):004:0> “foo.bar”.gsub ‘.’, “"
(irb):4: warning: string pattern instead of regexp; metacharacters no
longer eff
ective
"foo
bar”
irb(main):005:0>

There’s just this ugly warnig. Anyone know a way to switch that off?

Or you use Regexp.escape as others already have pointed out:

irb(main):017:0* “foo.bar”.gsub( /#{Regexp.escape(“.”)}/, “" )
"foo
bar”
irb(main):018:0>

Cheers

robert

“Andreas Schwarz” usenet@andreas-s.net schrieb im Newsbeitrag
news:slrnbhr0jv.d34.usenet@home.andreas-s.net

···

I wanted to do a simple string substitution, and was surprised to see
that there isn’t such a method in ruby. I can’t use String::(g)sub,
because the substitution mustn’t be influenced by special chars or
backreferences in the pattern and replacement strings. Of course I could
write functions to escape regex special chars in the pattern and
backreferences in the replacement string, but this is about the ugliest
solution I can think of.

Andreas


AVR-Tutorial, über 350 Links
Forum für AVRGCC und MSPGCC
http://www.mikrocontroller.net

It might help him, but I can understand how he feels… everytime I write
a pattern as a regexp which in the end just is a plain string, or a pattern
which would do with glob-style matching, I have the impression I’m throwing
cannons after pigeons again (nothing against your comp, guy :slight_smile:

-martin

···

On Wed, Jul 23, 2003 at 01:38:08AM +0900, ts wrote:

(…) Of course I could
write functions to escape regex special chars in the pattern and
backreferences in the replacement string, but this is about the ugliest
solution I can think of.

Well Regexp#escape don’t do what you want ?

ts wrote:

I wanted to do a simple string substitution, and was surprised to see
that there isn’t such a method in ruby. I can’t use String::(g)sub,
because the substitution mustn’t be influenced by special chars or
backreferences in the pattern and replacement strings. Of course I could
write functions to escape regex special chars in the pattern and
backreferences in the replacement string, but this is about the ugliest
solution I can think of.

Well Regexp#escape don’t do what you want ?

I would still need a function to remove backreferences from the
replacement string. It’s possible, of course, but it hurts me that I
have to use such “hacks” for a simple substitution.

···


AVR-Tutorial, über 350 Links
Forum für AVRGCC und MSPGCC
http://www.mikrocontroller.net

Dave Thomas wrote:

irb(main):006:0> a = “dave”
=> “dave”
irb(main):007:0> a[“av”] = “onat”
=> “onat”
irb(main):008:0> a
=> “donate”

Thanks, now I’m using the following methods:

class String

def simple_sub!(find, replace)
self[find] = replace
return true
rescue
return false
end

def simple_gsub!(find, replace)
c = 0
while self.simple_sub!(find, replace)
c += 1
end
return c
end

end

end

···


AVR-Tutorial, über 350 Links
Forum für AVRGCC und MSPGCC
http://www.mikrocontroller.net

Robert Klemme wrote:

“Andreas Schwarz” usenet@andreas-s.net schrieb im Newsbeitrag
news:slrnbhr0jv.d34.usenet@home.andreas-s.net

I wanted to do a simple string substitution, and was surprised to see
that there isn’t such a method in ruby. I can’t use String::(g)sub,
because the substitution mustn’t be influenced by special chars or
backreferences in the pattern and replacement strings. Of course I could
write functions to escape regex special chars in the pattern and
backreferences in the replacement string, but this is about the ugliest
solution I can think of.

Where’s the problem?

irb(main):004:0> “foo.bar”.gsub ‘.’, “"
(irb):4: warning: string pattern instead of regexp; metacharacters no
longer eff
ective
"foo
bar”

irb(main):001:0> “foo.bar”.gsub ‘.’, “"
=> "
******”

Or you use Regexp.escape as others already have pointed out:

irb(main):017:0* “foo.bar”.gsub( /#{Regexp.escape(“.”)}/, “" )
"foo
bar”

irb(main):007:0> “foo.bar”.gsub( /#{Regexp.escape(“.”)}/, “\1”)
=> “foobar”

···


AVR-Tutorial, über 350 Links
Forum für AVRGCC und MSPGCC
http://www.mikrocontroller.net

I would still need a function to remove backreferences from the
replacement string. It's possible, of course, but it hurts me that I
have to use such "hacks" for a simple substitution.

Perhaps with Regexp#escape

svg% ruby -e 'p "{}".gsub(/#{Regexp.escape("]{")}/, Regexp.escape("\\1"))'
"[\\1}"
svg%

Guy Decoux

Andreas Schwarz wrote:

while self.simple_sub!(find, replace)

Hmmm… any idea how I can stop this from getting an infinite loop?

“asdf”.simple_gsub!(“a”, “abc”)

···


AVR-Tutorial, über 350 Links
Forum für AVRGCC und MSPGCC
http://www.mikrocontroller.net

“Andreas Schwarz” usenet@andreas-s.net schrieb im Newsbeitrag
news:slrnbht3o8.2jq.usenet@home.andreas-s.net

Robert Klemme wrote:

“Andreas Schwarz” usenet@andreas-s.net schrieb im Newsbeitrag
news:slrnbhr0jv.d34.usenet@home.andreas-s.net

I wanted to do a simple string substitution, and was surprised to see
that there isn’t such a method in ruby. I can’t use String::(g)sub,
because the substitution mustn’t be influenced by special chars or
backreferences in the pattern and replacement strings. Of course I
could
write functions to escape regex special chars in the pattern and
backreferences in the replacement string, but this is about the
ugliest
solution I can think of.

Where’s the problem?

irb(main):004:0> “foo.bar”.gsub ‘.’, “"
(irb):4: warning: string pattern instead of regexp; metacharacters no
longer eff
ective
"foo
bar”

irb(main):001:0> “foo.bar”.gsub ‘.’, “"
=> "
******”

Ah, then it’s a ruby version thingy. I used 1.7.3. Which one do you
have?

Or you use Regexp.escape as others already have pointed out:

irb(main):017:0* “foo.bar”.gsub( /#{Regexp.escape(“.”)}/, “" )
"foo
bar”

irb(main):007:0> “foo.bar”.gsub( /#{Regexp.escape(“.”)}/, “\1”)
=> “foobar”

Why do you use \1 if you want to replace a fixed string? Or do you want
to insert \1? Then you shoul’ve done

“foo.bar”.gsub( /#{Regexp.escape(“.”)}/, Regexp.escape(“\1”) )

Cheers

robert

Apparently, ts recently wrote:

I would still need a function to remove backreferences from the A>
replacement string. It’s possible, of course, but it hurts me that I A>
have to use such “hacks” for a simple substitution.

Perhaps with Regexp#escape

svg% ruby -e ‘p “{}”.gsub(/#{Regexp.escape(“]{”)}/,
Regexp.escape(“\1”))’ “[\1}”
svg%

And then, so you don’t have to type that all every time, just make it a
method of String. Being able to do this is one of the best features of
Ruby. =)

class String
def simple_sub(from,to)
sub(/#{Regexp.escape(from)}/,Regexp.escape(to))
end
end

Wes

Robert Klemme wrote:

“Andreas Schwarz” usenet@andreas-s.net schrieb im Newsbeitrag
news:slrnbht3o8.2jq.usenet@home.andreas-s.net

irb(main):001:0> “foo.bar”.gsub ‘.’, “"
=> "
******”

Ah, then it’s a ruby version thingy. I used 1.7.3. Which one do you
have?

ruby 1.6.8

irb(main):007:0> “foo.bar”.gsub( /#{Regexp.escape(“.”)}/, “\1”)
=> “foobar”

Why do you use \1 if you want to replace a fixed string? Or do you want
to insert \1?

Yes.

Then you shoul’ve done

“foo.bar”.gsub( /#{Regexp.escape(“.”)}/, Regexp.escape(“\1”) )

irb(main):004:0> “foo.bar”.gsub( /#{Regexp.escape(“.”)}/, Regexp.escape(“.\1”) )
returns
“foo\.\1bar”
instead of
“foo.\1bar”

Is there really no easy way to replace strings in Ruby?

Apparently, Andreas Schwarz recently wrote:

Then you shoul’ve done

“foo.bar”.gsub( /#{Regexp.escape(“.”)}/, Regexp.escape(“\1”) )

irb(main):004:0> “foo.bar”.gsub( /#{Regexp.escape(“.”)}/,
Regexp.escape(“.\1”) ) returns
“foo\.\1bar”
instead of
“foo.\1bar”

Is there really no easy way to replace strings in Ruby?

One of the super smart people on this list already posted a much simpler
answer. I’ll parrot it 'cause it looks like a lot of people missed it:

irb(main):001:0> s = “foo.bar”
=> “foo.bar”
irb(main):002:0> s[‘.’] = ‘.\1’
=> “.\1”
irb(main):003:0> s
=> “foo.\1bar”
irb(main):004:0>

$ ruby -v
ruby 1.6.8 (2002-12-24) [i586-linux-gnu]
$ irb -v
irb 0.7.4(01/05/08)

Apparently, Andreas Schwarz recently wrote:

irb(main):004:0> "foo.bar".gsub( /#{Regexp.escape(".")}/,

                              ^^^^

irb(main):002:0> s['.'] = '.\1'

                     ^^^^^

You don't do the same : he want to use #gsub not #sub

Guy Decoux

ts wrote:

Apparently, Andreas Schwarz recently wrote:

irb(main):004:0> “foo.bar”.gsub( /#{Regexp.escape(“.”)}/,
^^^^

irb(main):002:0> s[‘.’] = ‘.\1’
^^^^^

You don’t do the same : he want to use #gsub not #sub

Exactly. The only solutions I can think of:

  1. use regex_escape() for the string that should be replaced, and
    remove backreferences in the replacement string manually

  2. do it char by char, like in C.

  3. is ugly, 2) is slow and even uglier.

···


AVR-Tutorial, über 350 Links
Forum für AVRGCC und MSPGCC
http://www.mikrocontroller.net

Andreas,

Exactly. The only solutions I can think of:

  1. use regex_escape() for the string that should
    be replaced, and remove backreferences in the
    replacement string manually
  2. do it char by char, like in C.
How about using the block form of String#gsub in combination with

Regexp.escape:

irb(main):001:0> “foo.bar”.gsub(Regexp.escape(‘.’)) { ‘.\1’ }
=> “foo.\1bar”

This eliminates the problems with backreferences in the replacement

string.

I hope this helps!

- Warren Brown

Moin!

Andreas Schwarz wrote:

Exactly. The only solutions I can think of:

  1. use regex_escape() for the string that should be replaced, and
    remove backreferences in the replacement string manually
  2. do it char by char, like in C.
  1. class String
    def simple_global_replace(find, replace)
    self.split(/(#{Regexp.quote(find)})/).map { |elm|
    elm == find ? replace : elm
    }.join(“”)
    end
    end

    “hello.world.bar”.simple_global_replace(“.”, “…”)

    => “hello…world…bar”

  1. is ugly, 2) is slow and even uglier.
  1. is slow and maybe even ugly.

Regards,
flgr