Tuesday, 15 April 2014

regex - Multiline vim regular expression replacement from range -



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