tags:

views:

95

answers:

4

i have a string like

/root/children[2]/header[1]/something/some[4]/table/tr[1]/links/a/b

and

/root/children[2]/header[1]/something/some[4]/table/tr[2]

how can i reproduce the string so that all the /\[\d+\]/ are removed except for the last /\[\d+\]/ ?

so i should end up with .

/root/children/header/something/some/table/tr[1]/links/a/b

and

/root/children/header/something/some/table/tr[2]
+1  A: 

We will have to use while loop, I guess. And here comes good ol' C-style-loop solution:

while s.gsub!(/(\[\d+\])(.*?)(\[\d+\])/, '\2\3'); end

It's a bit hard to read, so I'll explain. The idea is that we match the string with a pattern that requires two [\d+] blocks to persist in a string. In the replacement, we just delete the first one. We repeat it until string doesn't match (so it contains only one such block) and utilize the fact that gsub! doesn't perform substitution when string is unmatched.

Pavel Shved
Cleaner than mine, and about 5% faster. +1
Bob Aman
Just don't forget to put a comment on that puppy.
Bob Aman
See Charles Dale's for a better answer...
glenn mcdonald
A: 

I'm absolutely certain there's a more elegant solution, but this ought to get you going:

string = "/root/children[2]/header[1]/something/some[4]/table/tr[1]/links/a/b"
count = string.scan(/\[\d+\]/).size
index = 0
string.gsub(/\[\d+\]/) do |capture|
  index += 1
  index == count ? capture : ""
end
Bob Aman
+2  A: 

No loops for you. Use a lookahead assertion (?= ... ):

s.gsub(/\[\d+\](?=.*\[)/, "")

There's a reasonable explanation of the very useful lookaround operators here

Charles Dale
Exactly. You posted this while I was typing the same solution, identical except you put a helpful space before the ""!
glenn mcdonald
Oh, and I did the speed check, and this version is almost twice as fast as Pavel's while loop...
glenn mcdonald
Nice one Glenn. It's an important space that one =P.
Charles Dale
It should be `s.gsub!(/\[\d+\](?=.*\[\d+\])/, "")`. Still twice faster?
Pavel Shved
A: 

str.scan(/[\d+]/)[0..-2].each {|match| str.sub!(match, '')}

leomayleomay