From: Robert Klemme Date: 2009-06-27T03:50:13+09:00 Subject: Re: Is there a way to abandon a gsub if you're using a block? On 26.06.2009 18:14, Wes Gamble wrote: > Robert Klemme wrote: >> If you provide more detail about the input and the text that you want >> to match we might be able to help fix the regular expression. IMHO >> that approach is superior to simply returning the match effectively >> replacing it with itself (which does work of course). > > self.html.gsub!(/]*?href=(['"]) # href=' or href=" > (?!mailto:)(.*?) #Contents of any non-mailto: > href attribute > \1.*?> #End of href attribute (same > quote) + arbitrary text to end of opening tag > (.*?) #Contents of - the "link > display" > <\\?\/a>/mix) { #Closing tag, allowing > for optional \, e.g. or <\/a> > > So, this regex is attempting to pull out the contents of an href in a > tag, as well as the content enclosed by the tag. > > The problem comes when it encounters a particularly nefarious kind of > HTML which looks like this: > >
........
> > and there is no closing for the first anchor. What I want to pull > is the _valid_ tag "on the inside", but what I get is the first > tag up to the closing tag, which is not correct. The problem is > that the first tag just shouldn't be there at all. Another way to put it is that you want to match ... without any intermediate . > So I need to modify my regex to not match if there is a tag inside > of another one. I tried for about 30 minutes yesterday using a (?!) > assertion, but couldn't quite get it. So the basic pattern here is that you want to match a combination A...B without any A in between. We try with a simple example: irb(main):005:0> s = '....A;;A+++B' => "....A;;A+++B" irb(main):006:0> s.scan %r{A(?:.(?!A))+B} => ["A+++B"] Now with HTML like string: irb(main):008:0> t = s.gsub(/A/, '').gsub(/B/, '') => "....;;+++" irb(main):017:0> t.scan %r{(?:.(?!}i => ["+++"] A bit more readable irb(main):024:0> t.scan %r{ irb(main):025:0/ # opening tag irb(main):026:0/ (?:.(?! and irb(main):027:0/ # closing tag irb(main):028:0/ }mix => ["+++"] The trick is to have a negative lookahead assertion on *each* character between the beginning and ending sequence. Thus avoiding a match if the opening sequence appears anywhere in between. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/