Remove everything except regex match in Vim

前端 未结 4 555
深忆病人
深忆病人 2020-11-29 04:22

My specific case is a text document that contains lots of text and IPv4 addresses. I want to remove everything except for the IP addresses.

I can use :vglobal<

相关标签:
4条回答
  • 2020-11-29 04:34

    This effect can be accomplished by using sub-replace-special substitution and setreg() linewise

    :let @a=""
    :%s//\=setreg('A', submatch(0), 'l')/g
    :%d _
    :pu a
    :0d _
    

    or all in one line as such:

    :let @a=""|%s//\=setreg('A', submatch(0), 'l')/g|%d _|pu a|0d _
    

    Overview: Using a substitution to append each match into register "a" linewise then replace the entire buffer with the contents of register "a"

    Explanation:

    1. let @a="" empty the "a" register that we will be appending into
    2. %s//\=setreg('A', submatch(0), 'l')/g substitute globally using the last pattern
    3. the \=expr will replace the pattern with the contents of the expression
    4. submatch(0) get the entire string of what just matched
    5. setreg('A', submatch(0), 'l') append (note: the capital "a") to @a the matched string, but linewise
    6. %d _ delete every line into the black hole register (aka @_)
    7. pu a put the contents of @a into the buffer
    8. 0d _ delete the first line

    Concerns:

    • This will trash one of your registers. This example trashed @a
    • Uses the last search pattern. Although you can modify the substitute command with whatever pattern you want: %s/<pattern>/\=setreg('A', submatch(0), 'l')/g

    For more help

    :h :s\=
    :h :let-@
    :h submatch()
    :h setreg()
    :h :d
    :h :p
    
    0 讨论(0)
  • 2020-11-29 04:44

    Assuming <ip> is your regex to match an IP address, I presume you could do something like :

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

    where \1 is the first matched group (the address alone), and .\{-} used for non-greedy matching.

    0 讨论(0)
  • 2020-11-29 04:54
    :set nowrapscan
    :let @a=""
    gg0qac/\v(\d{1,3}\.){3}\d{1,3}<CR><CR><Esc>//e+1<CR>@aq@adG
    

    Explanation:

    1. set nowrapscan disables ability to seek «past the end of file».
    2. let @a="": empty the a register.
    3. gg0: go to the first column (0) of the first line (gg).
    4. qa: start writing macros.
    5. c/{pattern}<CR>: change until pattern.
    6. c{motion}<CR><ESC>: replace text with newline (here {motion} is /{pat}<CR>).
    7. //e+1<CR>: search for last pattern, go one character left past its end (wraps around a newline, but if your lines looks like this: IP<newline>IP, there may be problems).
    8. @a: execute @a macros (it is empty when you are recording it, but when you are finished it will repeat steps 1-7 until it gets an error).
    9. q: end recording @a.
    10. @a: execute @a macros.
    11. dG: delete to the end of file.
    0 讨论(0)
  • 2020-11-29 04:58

    In short, I'm looking for a way to do this without leaving vim

    Easy enough:

    :1,$! grep --extended-regexp --only-matching --regexp="([0-9]{1,3}\.){3}[0-9]{1,3}"
    

    (though I actually voted up icecrime's substitution answer)

    0 讨论(0)
提交回复
热议问题