How to extract specific paragraphs from text using vim?

I try to extract a test from a huge file containing text in this format several times

CL blahblahblah SP blahblahblah blahblahblah blahblahblah DE blahblahblahblahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah AB blahblahblah blahblahblah blahblahblah blahblahblahblahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah C1 blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah lahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah RP blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah EM blahblahblah blahblahblah blahblahblah blahblahblah NR blahblahblah blahblahblah blahblahblah blahblahblah TC blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah Z9 blahblahblah blahblahblah blahblahblah blahblahblah PU blahblahblah blahblahblah blahblahblah blahblahblah PI blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah 

I'm only interested in entries starting with C1, AB, TI, but sometimes they span multiple lines, and the lines of the XX tag that follow them are not always the same. Is there an easy way to save only these records? So my remaining text should look like this:

 TI blahblahblah AB blahblahblah b lah blahblah blah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah C1 blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah TI blah blah blah blah blah blah AB blahblahblah blahblahblah blahblahblah blahblahblahblahblahblah blahblahblah blahblahblah blahblahblah blahblahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah C1 blahblahblah blahblahblah blahblahblah blahblahblahblahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah 

etc.

Many thanks!

+4
source share
5 answers

I would do:

 :$put='X' | 1,$-1g/^\(\s\|C1\|AB\|TI\)\@!/ ,/^\S/-d :$d 

This will do the following:

  • Insert a line containing "X" at the end
  • for each line except the last ( 1,$-1 ), if it starts with non-space and does not start with C1, AB or TI ( g/pattern/ ), delete ( d ) until the next line that does not start with a space ,/pattern/ not included ( - , which is less for -1 )
  • delete line "X" at the end

To try if you use Gvim:

  • Copy this code to the clipboard
  • in Gvim run :@+ (which plays Ex commands from the register + associated with the clipboard).

What I got:

 AB blahblahblah blahblahblah blahblahblah blahblahblahblahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah C1 blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah lahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah 
+3
source

This should work:

 :let @a="" | g/^\v<(C1|AB|TI)>/norm! "Ay/^\S^M 

EDIT . For Windows: you need to add "return" to this line, type ^M as Cq Enter (or Cv if you are not using Windows or your vimrc does not install behave mswin )

Returns strings in case "a . To replace the buffer with these strings:

 :%d | put a 

Or, put it in a new buffer:

 :new | put a 
+3
source

awk solution:

 awk ' BEGIN{ tags["C1"] tags["AB"] tags["TI"] } { match($0, /^\w+/) if(RSTART) t=substr($0, RSTART, RLENGTH) } t in tags' input.txt 

Translate to vim command:

 :g/^/let t=matchstr(getline('.'), '^\w\+') | if !empty(t) | let tag=t | endif | if index(['C1', 'AB', 'TI'], tag)==-1 | d | endif 
+3
source

This seems to work, but there is an empty line at the end of the file.

 :%s/\v^(C1|AB|TI|\s)@!\_.{-}\n(C1|AB|TI|$)@=// 

This regex uses several complex functions, I will try to explain.

  • \v says the pattern is "very magical", just allowing us to skip the backslash in several places.
  • ^(C1|AB|TI|\s)@! matches any string that does not start with target tags or spaces.
  • \_. matches any character, including newlines.
  • {-} matches the previous atom as little as possible (not greedy).
  • \n matches the end of a line.
  • (C1|AB|TI|$)@= matches the target tags or the end of the line (for the end case) with zero width.

Result with your test input:

 AB blahblahblah blahblahblah blahblahblah blahblahblahblahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah C1 blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah blahblahblah 
+2
source

another awk onliner:

 awk -F' |\t' '{if($1)f=$1~/CI|AB|C1/?1:0}f' yourFile 
0
source

Source: https://habr.com/ru/post/1396591/


All Articles