regex - Multiline vim regular expression replacement from range -
i attempting reformat hierarchical (xml) file "per line" file using vim.
here simplified example. real case "large" (500k lines) , entries , groups arbitrary counts.
input file:
<group key="abc"> <entry val="1"/> <entry val="2"/> <entry val="3"/> </group> <group key="xyz"> <entry val="1"/> <entry val="2"/> <entry val="3"/> <entry val="4"/> <entry val="5"/> </group>
output result:
abc,1 abc,2 abc,3 xyz,1 xyz,2 xyz,3 xyz,4 xyz,5
please note don't need single magic look of (although that'd swell). part struggling getting key associated each of entries. i'm sure there idiom handling this. in advance.
one thing tried , may useful others follows:
:g/key="\(.*\)"/.;/<\/group/s/<entry /\1,<entry /g
which not work because range match not carried on substitution. look looks pat1, builds range there pat2, substitutes pat3 pat4 (but within instances of pat1,pat2 range inclusive).
:g/pat1/.;/pat2/s/pat3/pat4/g
solution
the best solution below solved looking entry , backwards key, opposed trying above building range , multiple substitutions. worked required minor modifications, provided here others. commands heavy lifting are:
:g/entry/?key?,\?t. :g/entry/norm ddpkj :v/entry/d
breakdown:
search entry lines:
:g/entry/
from there, search backwards the line has key , re-create below each entry.
?key?,\?t.
search entry lines again, , switch normal mode editing
:g/entry/norm
swap 2 lines (delete key line , paste below grouping line). move key line , bring together 2 lines.
ddpkj
once keys mapped, search lines not have entry , delete them.
:v/entry/d
if have multiple hierarchies do, can run first 2 lines multiple times. 1 time on single line, straightforward clean whatever final format needed. major benefit solution can set in script , rerun with
vim -s script.vim data.file
following work
:g/entry/?<group?,?<group?t. :%norm j :g/<\//d :%norm df"f"df"i,<c-v><esc>f"d$
breakdown
for each line containing entry
, search backwards <group
, re-create line below entry
:g/entry/?<group?,?<group?t. <group key="abc"> <entry val="1"/> <group key="abc"> <entry val="2"/> <group key="abc"> <entry val="3"/> <group key="abc"> </group> <group key="xyz"> <entry val="1"/> <group key="xyz"> <entry val="2"/> <group key="xyz"> <entry val="3"/> <group key="xyz"> <entry val="4"/> <group key="xyz"> <entry val="5"/> <group key="xyz"> </group>
join lines
:%norm j <group key="abc"> <entry val="1"/> <group key="abc"> <entry val="2"/> <group key="abc"> <entry val="3"/> <group key="abc"> </group> <group key="xyz"> <entry val="1"/> <group key="xyz"> <entry val="2"/> <group key="xyz"> <entry val="3"/> <group key="xyz"> <entry val="4"/> <group key="xyz"> <entry val="5"/> <group key="xyz"> </group>
remove closing tags
:g/<\//d <group key="abc"> <entry val="1"/> <group key="abc"> <entry val="2"/> <group key="abc"> <entry val="3"/> <group key="xyz"> <entry val="1"/> <group key="xyz"> <entry val="2"/> <group key="xyz"> <entry val="3"/> <group key="xyz"> <entry val="4"/> <group key="xyz"> <entry val="5"/>
fixup remaining text searching , deleting , quotes. note <c-v><esc>
key sequence add together escape in command.
:%norm df"f"df"i,<c-v><esc>f"d$ abc,1 abc,2 abc,3 xyz,1 xyz,2 xyz,3 xyz,4 xyz,5
regex vim multiline
No comments:
Post a Comment