Удалить все, кроме регулярного выражения в Vim
Моим конкретным случаем является текстовый документ, который содержит много текстовых и IPv4-адресов. Я хочу удалить все, кроме IP-адресов.
Я могу использовать :vglobal
для поиска ([0-9]{1,3}\.){3}[0-9]{1,3}
и удалить все строки без IP-адресов, но после этого я знаю только, как искать всю строку и выбирать соответствующий текст. Есть ли более простой способ.
Короче говоря, я ищу способ сделать следующее без использования внешней программы (например, grep):
grep --extended-regexp --only-matching --regexp="([0-9]{1,3}\.){3}[0-9]{1,3}"
Вызов grep из vim может потребовать адаптации моего регулярного выражения (например: удаление \v). Использование инкрементного поиска vim показывает мне, что у меня есть правильный шаблон, и я не хочу проверять свое регулярное выражение в grep тоже.
Изменить: Благодаря Петру, здесь функция, которую я сейчас использую. (C - это регистр, который я обычно clobber в моих функциях.)
"" Remove all text except what matches the current search result
"" The opposite of :%s///g (which clears all instances of the current search).
function! ClearAllButMatches()
let old = @c
let @c=""
%s//\=setreg('C', submatch(0), 'l')/g
%d _
put c
0d _
let @c = old
endfunction
Edit2: Я сделал команду, которая принимает диапазоны (но по умолчанию - весь файл).
"" Remove all text except what matches the current search result. Will put each
"" match on its own line. This is the opposite of :%s///g (which clears all
"" instances of the current search).
function! s:ClearAllButMatches() range
let is_whole_file = a:firstline == 1 && a:lastline == line('$')
let old_c = @c
let @c=""
exec a:firstline .','. a:lastline .'sub//\=setreg("C", submatch(0), "l")/g'
exec a:firstline .','. a:lastline .'delete _'
put! c
"" I actually want the above to replace the whole selection with c, but I'll
"" settle for removing the blank line that left when deleting the file
"" contents.
if is_whole_file
$delete _
endif
let @c = old_c
endfunction
command! -range=% ClearAllButMatches <line1>,<line2>call s:ClearAllButMatches()
Ответы
Ответ 1
Этот эффект может быть достигнут с помощью замены подзамены-специальной замены и setreg()
linewise
:let @a=""
:%s//\=setreg('A', submatch(0), 'l')/g
:%d _
:pu a
:0d _
или все в одной строке как таковой:
:let @a=""|%s//\=setreg('A', submatch(0), 'l')/g|%d _|pu a|0d _
Обзор. Используя подстановку для добавления каждого совпадения в регистр "a", затем замените весь буфер содержимым регистра "a"
Пояснение:
-
let @a=""
запустите регистр "a", который мы добавим в
-
%s//\=setreg('A', submatch(0), 'l')/g
заменить глобально, используя последний шаблон
-
\=expr
заменит шаблон содержимым выражения
-
submatch(0)
получить всю строку того, что только что сопоставлено
-
setreg('A', submatch(0), 'l')
append (примечание: капитал "a" ) к @a совпадающей строке, но linewise
-
%d _
удалите каждую строку в регистр черных дыр (aka @_)
-
pu a
помещает содержимое @a в буфер
-
0d _
удалить первую строку
Заботы:
- Это приведет к удалению одного из ваших регистров. В этом примере trashed @a
- Использует последний шаблон поиска. Хотя вы можете изменить команду substitute любым желаемым шаблоном:
%s/<pattern>/\=setreg('A', submatch(0), 'l')/g
Для получения дополнительной справки
:h :s\=
:h :[email protected]
:h submatch()
:h setreg()
:h :d
:h :p
Ответ 2
Предполагая, что <ip>
является вашим регулярным выражением в соответствии с IP-адресом, я полагаю, вы могли бы сделать что-то вроде:
:%s/.\{-}\(<ip>\).*/\1/g
где \1
- первая совпадающая группа (только адрес) и .\{-}
используется для не-жадного соответствия.
Ответ 3
:set nowrapscan
:let @a=""
gg0qac/\v(\d{1,3}\.){3}\d{1,3}<CR><CR><Esc>//e+1<CR>@[email protected]
Пояснение:
-
set nowrapscan
отключает возможность поиска "мимо конца файла".
-
let @a=""
: пустой регистр.
-
gg0
: перейдите к первому столбцу (0) первой строки (gg).
-
qa
: начните писать макросы.
-
c/{pattern}<CR>
: изменить до шаблона.
-
c{motion}<CR><ESC>
: замените текст на новую строку (здесь {motion}
есть /{pat}<CR>
).
-
//e+1<CR>
: найдите последний шаблон, перейдите на один символ слева от его конца (обертывает новую строку, но если ваши строки выглядят так: IP<newline>IP
, могут быть проблемы).
-
@a
: выполнить @a
макросы (при его записи он пуст, но когда вы закончите, он повторит шаги с 1 по 7, пока не получится ошибка).
-
q
: конец записи @a
.
-
@a
: выполнить макросы @a
.
-
dG
: удалить до конца файла.
Ответ 4
Короче говоря, я ищу способ сделать это, не выходя из vim
достаточно просто:
:1,$! grep --extended-regexp --only-matching --regexp="([0-9]{1,3}\.){3}[0-9]{1,3}"
(хотя я фактически проголосовал за ответ на замену icecrime)