Как "применить" обратные символы в текстовом файле (в идеале в vim)
У меня есть файл журнала с обратными символами в нем (^ H). Я просматриваю файл в Vim, и может быть довольно сложно понять, что происходит.
В идеале я бы хотел "применить" все ^ H в заданной строке/диапазоне, чтобы я мог видеть конечный результат.
Я бы предпочел сделать это внутри Vim по очереди, но решение, которое преобразует весь файл, лучше, чем ничего.
Ответы
Ответ 1
Включите параметр "вставить" (используя :set paste
), а затем нажмите dd i <CTRL-R> 1 <ESC>
в каждой строке, к которой вы хотите применить обратные пространства. Это также работает, если вы удаляете несколько строк или даже весь файл.
Ключ здесь состоит в том, что вы используете <CTRL-R> 1
в режиме вставки, чтобы "вывести" содержимое регистра 1 (где только что удалили ваши удаленные строки) и опция "вставить" предотвращает Vim из любых сопоставлений или сокращений.
Ответ 2
Упрощенный ответ:
:%s/[^^H]^H//g
где ^^ H:
- Литеральный символ
- Ctrl-V Ctrl-H
и повторите его пару раз (пока vim не скажет вам, что никаких замещений не было сделано
Если вы хотите без повторения, и вы не против использовать%! perl:
%!perl -0pe 's{([^\x08]+)(\x08+)}{substr$1,0,-length$2}eg'
Все символы являются буквальными - т.е. вам не нужно делать ctrl-v... в любом месте над строкой.
Должен работать в большинстве случаев.
Ответ 3
Я искал это, пытаясь вспомнить команду, которую я использовал раньше, чтобы "применить" обратные пространства, а затем я это вспомнил: col -b - вот страницы руководства. (Он делает немного больше и исходит из BSD или более точно AT & T UNIX, поскольку manpage говорит, поэтому, если вы находитесь в Linux, вам может потребоваться установить дополнительный пакет, на debian в bsdmainutils.)
Ответ 4
Хорошо, вот голое решение.
Скопируйте этот код в файл с именем crush.c:
#include <stdio.h>
// crush out x^H sequences
// there was a program that did this, once
// cja, 16 nov 09
main()
{
int c, lc = 0;
while ((c = getchar()) != EOF) {
if (c == '\x08')
lc = '\0';
else {
if (lc)
putchar(lc);
lc = c;
}
}
if (lc)
putchar(lc);
}
Скомпилируйте этот код с вашим любимым компилятором:
gcc crush.c -o crush
Затем используйте его так, чтобы сокрушить эти назойливые последовательности:
./crush <infilename >outfilename
Или использовать его в конвейере ( "скажем" - это приложение "речь-текст" на Mac)
man date | ./crush | say
Вы можете скопировать раздачу в ваш любимый исполняемый каталог (/usr/local/bin или некоторые такие), а затем ссылаться на него следующим образом
man date | crush | say
Ответ 5
Просто удалите все вхождения. ^ H (где. является интерпретацией регулярных выражений.):
:s/.^H//g
(вставьте ^ H буквально, введя Ctrl-V Ctrl-H)
Это применимо к текущей строке. Используйте любой диапазон, который вы хотите, если хотите применить его к другим строкам.
Как только вы выполнили одну команду :s...
, вы можете повторить на другой строке, просто набрав :sg
(вам нужно, чтобы g в конце повторного применения ко всем вхождениям в текущей строке).
Ответ 6
Как насчет следующей функции? Я использовал \%x08 вместо ^ H, так как проще скопировать и вставить полученный код. Вы можете ввести его и использовать Ctrl - V Ctrl - H, если хотите, но я думал, что \%x08 может быть проще. Это также пытается обрабатывать промежутки в начале строки (они просто удаляют их).
" Define a command to make it easier to use (default range is whole file)
command! -range=% ApplyBackspaces <line1>,<line2>call ApplyBackspaces()
" Function that does the work
function! ApplyBackspaces() range
" For each line in the selected lines
for index in range(a:firstline, a:lastline)
" Get the line as a string
let thisline = getline(index)
" Remove backspaces at the start of the line
let thisline = substitute(thisline, '^\%x08*', '', '')
" Repeatedly apply backspaces until there are none left
while thisline =~ '.\%x08'
" Substitute any character followed by backspace with nothing
let thisline = substitute(thisline, '.\%x08', '', 'g')
endwhile
" Remove any backspaces left at the start of the line
let thisline = substitute(thisline, '^\%x08*', '', '')
" Write the line back
call setline(index, thisline)
endfor
endfunction
Использовать с:
" Whole file:
:ApplyBackspaces
" Whole file (explicitly requested):
:%ApplyBackspaces
" Visual range:
:'<,'>ApplyBackspaces
Для получения дополнительной информации см.
:help command
:help command-range
:help function
:help function-range-example
:help substitute()
:help =~
:help \%x
Изменить
Обратите внимание: если вы хотите работать с одной строкой, вы можете сделать что-то вроде этого:
" Define the command to default to the current line rather than the whole file
command! -range ApplyBackspaces <line1>,<line2>call ApplyBackspaces()
" Create a mapping so that pressing ,b in normal mode deals with the current line
nmap ,b :ApplyBackspaces<CR>
или вы можете просто сделать:
nmap ,b :.ApplyBackspaces<CR>
Ответ 7
Здесь фильтр Bash, который вы можете использовать для обработки всего файла:
#!/bin/bash
while read LINE; do
while [[ "$LINE" =~ '^H' ]]; do
LINE="${LINE/[^^H]^H/}"
done
echo "$LINE"
done
Обратите внимание, что там, где появляется ^ H, он вводится в vim с помощью CTRL-v CTRL-h, а ^^ H вводится как SHIFT-6 CTRL-v CTRL-h.
Ответ 8
Здесь гораздо более быстрый фильтр Awk, который делает то же самое:
#!/usr/bin/awk -f
function crushify(data) {
while (data ~ /[^^H]^H/) {
gsub(/[^^H]^H/, "", data)
}
print data
}
crushify($0)
Обратите внимание, что, когда появляется ^^ H, первая каретка в ^^ H является кареткой (shift-6), а вторая каретка с H вводится (в vim), набирая CTRL-v CTRL-H