如何在文本文件中“应用”退格字符(理想情况下是在vim中)

时间:2009-08-19 09:14:45

标签: vim text

我有一个带有退格字符的日志文件(^ H)。我正在查看Vim中的文件,很难看到发生了什么。

理想情况下,我希望能够“应用”给定行/范围内的所有^ H,以便我可以看到最终结果。

我宁愿在Vim中逐行进行此操作,但是转换整个文件的解决方案总比没有好。

8 个答案:

答案 0 :(得分:12)

启用“粘贴”选项(使用 :set paste ),然后在要应用的每一行上按 dd i <CTRL-R> 1 <ESC> 退格到。如果删除多行,甚至整个文件,这也有效。

这里的关键是你在插入模式下使用 <CTRL-R> 1 来“输出”寄存器1的内容(你的删除行刚被放入)和'粘贴'选项可防止Vim使用任何映射或缩写。

答案 1 :(得分:9)

我试图记住我之前用来“应用”退格键的命令,然后我记得它: col -b - 这里是manpage。 (它更多地来自BSD或者更确切地说是AT&amp; T UNIX,如联机帮助页所示,所以如果你在Linux上,你可能需要在 bsdmainutils 上的debian上安装一个额外的软件包。 )

答案 2 :(得分:8)

简单回答:

:%s/[^^H]^H//g

其中^^ H是:

  1. 字面^字符
  2. Ctrl-V Ctrl-H
  3. 并重复几次(直到vim会告诉你没有替换

    如果您不想重复,并且不介意使用%!perl:

    %!perl -0pe 's{([^\x08]+)(\x08+)}{substr$1,0,-length$2}eg'
    

    所有字符都是字面的 - 即您不必在上面的任何位置执行ctrl-v ...

    在大多数情况下应该有效。

答案 3 :(得分:1)

好的,这是一个裸机解决方案。

将此代码复制到名为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

您可以将crush复制到您喜欢的可执行文件目录(/ usr / local / bin或其他类似文件),然后按如下方式引用它

  man date | crush | say

答案 4 :(得分:0)

只需删除所有出现的。^ H(其中。是。的正则表达式解释):

:s/.^H//g

(通过输入Ctrl-V Ctrl-H逐字插入^ H)

这将适用于当前行。如果要将其应用于其他行,请使用您想要的任何范围。

完成一个:s...命令后,只需键入:sg即可在另一行重复(您需要在结尾处重新应用于当前行上的所有匹配项)。 / p>

答案 5 :(得分:0)

以下功能怎么样?我使用\%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>

答案 6 :(得分:0)

这是一个基于Bash的过滤器,可用于处理整个文件:

#!/bin/bash
while read LINE; do
  while [[ "$LINE" =~ '^H' ]]; do
    LINE="${LINE/[^^H]^H/}"
  done  
  echo "$LINE"
done

请注意,出现 ^ H 的地方,使用CTRL-v CTRL-h将其输入vim,输入 ^^ H 作为SHIFT-6 CTRL- v CTRL-h。

答案 7 :(得分:0)

这是一个更快的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 <通过键入CTRL-v CTRL-H

输入/ em>(进入vim)