Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vim - sed like labels or replacing only within pattern

Tags:

regex

vim

sed

label

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.

like image 903
yatsek Avatar asked Aug 16 '26 11:08

yatsek


2 Answers

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.

like image 145
melpomene Avatar answered Aug 18 '26 01:08

melpomene


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.

like image 31
Kent Avatar answered Aug 17 '26 23:08

Kent



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!