0

I have an html table with some headers:

<th>Header01</th>
...
<th>Different Header 20</th>

I'd like to find and replace everything between the first > and the next < with {{ }}:

<td>{{   }}</td>
...
<td>{{   }}</td>

I know I can use :s/\%Vth/td/g to replace all the th with td, but how can I use Vim's regex to find and replace everything between > and < with {{ }}?

I have attempted the following without success

:s/\%V\>(.*?)\</{{   }}/g
Scott Skiles
  • 3,647
  • 6
  • 40
  • 64
  • Do not escape `<` and `>`. Lazy quantifier in Vim is `{-}`. Try `s/\v>.{-}{{ }}/g` – Wiktor Stribiżew Aug 03 '18 at 13:40
  • 4
    As a general rule, [you shouldn't use regex to parse HTML](https://stackoverflow.com/a/590789/4934172). It might work for a simple HTML but using an HTML parser is usually a better idea. – 41686d6564 stands w. Palestine Aug 03 '18 at 13:48
  • Ok, `%s/>\(.\{-}\)>{{ \1 }} – Wiktor Stribiżew Aug 03 '18 at 13:56
  • To be clear, I am doing a find and replace while in Vim visual selection mode. Does this make a difference? I'm a little confused on the warning @AhmedAbdelhameed. I am not trying to parse HTML with regex, I am trying to find and replace in visual selection mode for lines where I know that the characters '>' and '<' exist. Is this the same thing? – Scott Skiles Aug 03 '18 at 14:16
  • 1
    It just means you understand that the regex cannot fit all kinds of mark-up language syntax and there will be edge cases when regex might find something you do not want, or vice versa. – Wiktor Stribiżew Aug 03 '18 at 14:18
  • 1
    @ScottSkiles You will just need to be a little bit careful when doing "find and replace" with regex (on HTML) because your regex might not match what you think it will (in some cases) specially if you have some complicated HTML. – 41686d6564 stands w. Palestine Aug 03 '18 at 14:19
  • Thanks for the help! Makes sense. I'll accept an answer shortly. – Scott Skiles Aug 03 '18 at 14:23

4 Answers4

1

You may use

%s/>\(.\{-}\)</>{{ \1 }}</g

In a non-very magic mode, \< and \> are word boundaries that is why they did not work on your side. Besides, *?, a Perl-like lazy quantifier, should be written as \{-} in Vim. The % symbol at the start tells Vim to search and replace on all lines, not just the current one.

Details

  • > - matches a >
  • \(.\{-}\) - captures into Group 1 any 0 or more chars (but linebreaks, if you need to include line breaks, prepend . with \_) but as few as possible
  • < - matches a <

The replacement is >{{ \1 }}<, >{{, Group 1 value and }}>. g makes multiple search and replace operations on lines.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
1

if you would take the risk of changing a html/vim by regex, in vim, you can just do:

%s/>[^<]*</>{{ & }}</g
Kent
  • 189,393
  • 32
  • 233
  • 301
  • What is the risk you're referring to @Kent? – Scott Skiles Aug 03 '18 at 14:08
  • @ScottSkiles [The one Ahmed warned you of](https://stackoverflow.com/a/590789/4934172). – Wiktor Stribiżew Aug 03 '18 at 14:09
  • 1
    @ScottSkiles for example you have `<![CDATA[.....` crossing multiple lines, or there were `
    ,

    etc` in one `

    ..` well, you know your input best, if you are sure it will work, just do it.
    – Kent Aug 03 '18 at 14:10
  • Ahh thank you both. I did not see the initial comment from Ahmed. – Scott Skiles Aug 03 '18 at 14:11
  • @Kent, I modified the above to run in Vim's visual mode, only selecting the lines that I want to change. Is this still dangerous? – Scott Skiles Aug 03 '18 at 14:18
  • @ScottSkiles I rejected your edit. because, if you selected lines, when you pressed `:`, the range will be there automatically. `%V` is for matching, not for ranging. again, it is risky, no matter if it will apply on selected lines or whole file, the point is, it is not good in general to change html/xml with regex – Kent Aug 03 '18 at 14:28
  • @Kent - Okay! Thanks for the edit reject explanation. Does it make a difference if this is modifying HTML tags in a Django template as opposed to an xml/html file? Still trying to grock the concept. – Scott Skiles Aug 03 '18 at 14:33
0

I may be misreading the question, but it appears the desired replacement text is paired double braces around 3 whitespaces (not around the original matched text: "replace everything between the first > and the next < with {{ }}". If correct, then the following simple substitute command should work:

%s/>.*</>{{   }}</g
rgt47
  • 316
  • 1
  • 4
0

If you have just one tag --> content per line, you can do:

:%norm cit{{ }}

As you would know, "cit" is a vim text-object that stands for "Change Inner Tag". If you have many tags on each line you can try:

:%s,>\zs[^<]*\ze</.*,{{ }},g

For more read :h text-objects and :h \zs

SergioAraujo
  • 11,069
  • 3
  • 50
  • 40