3

On the basis of some html editing I've came up with need for help from some VIM master out there.

I wan't to achieve simple task - I have html file with mangled urls.

<a href="http://some/wrong/url with variable number of spaces">Just description</a> <a href="http://some/wrong/url with three spaces">Just description</a>
...
<a href="http://anoter/wrong/url with completely other number of spaces">Just description</a>

Unfortunately it's not "one url per line".

I am aware of three approaches:

  1. I would like to be able to replace only within '"http://[^"]*"' regex (similar like replace only in matching lines - but this time not whole lines but only matching pattern should be involved)

  2. Or use sed-like labels - I can do this task with sed -e :a -e 's#\("http://[^" ]*\) \([^"]*"\)#\1_\2#g;ta'

  3. Also I know that there is something like "\@<=" but I am non native speaker and vim manual on this is beyond my comprehension.

All help is greatly appreciated.

If possible I would like to know answer on all three problems (as those are pretty interesting and would be helpful in other tasks) but either of those will do.

Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
yatsek
  • 855
  • 1
  • 10
  • 19

2 Answers2

3

Re: 1. You can replace recursively by combining vim's "evaluate replacement as an expression" feature (:h :s\=) with the substitute function (:h substitute()):

:%s!"http://[^"]*"!\=substitute(submatch(0), ' ', '_', 'g')!g

Re: 2. I don't know sed so I can't help you with that.

Re: 3. I don't see how \@<= would help here. As for what it does: It's equivalent to Perl's (?<=...) feature, also known as "positive look-behind". You can read it as "if preceded by":

:%s/\%(foo\)\@<=bar/X/g

"Replace bar by X if it's preceded by foo", i.e. turn every foobar into fooX (the \%( ... \) are just for grouping here). In Perl you'd write this as:

s/(?<=foo)bar/X/g;

More examples and explanation can be found in perldoc perlretut.

melpomene
  • 84,125
  • 8
  • 85
  • 148
1

I think what you want to do is to replace all spaces in your http:// url into _.

To achieve the goal, @melpomene's solution is straightforward. You could try it in your vim.

On the other hand, if you want to simulate your sed line, you could try followings.

:let @s=':%s#\("http://[^" ]*\)\@<= #_#g^M'

^M means Ctrl-V then Enter

then

200@s

this works in same way as your sed line (label, do replace, back to label...) and @<= was used as well.

one problem is, in this way, vim cannot detect when all match-patterns were replaced. Therefore a relative big number (200 in my example) was given. And in the end an error msg "E486: Pattern not found..." shows.

A script is needed to avoid the message.

Kent
  • 189,393
  • 32
  • 233
  • 301