2009-08-19 8 views
10

Tengo un archivo de registro con caracteres de retroceso en él (^ H). Estoy mirando el archivo en Vim y puede ser bastante difícil ver lo que está pasando.Cómo "aplicar" caracteres de retroceso dentro de un archivo de texto (idealmente en vim)

Idealmente, me gustaría ser capaz de "aplicar" todos los^H en una línea/rango determinado para que pueda ver el resultado final.

Prefiero hacer esto dentro de Vim line-by-line, pero una solución que convierta todo el archivo es mejor que nada.

+0

Por curiosidad, ¿cuál es el propósito de los^H caracteres?¿Qué se supone que deben lograr, ya sea en una copia impresa o en la consola? –

+0

@ John Saunders: en las impresoras antiguas, causaron sobreimpresiones que permitían hacer negrita por repetición: x^Hx^Hx^Hx o subrayado: _^Ha_^Hb_^Hc. "menos" en Linux se utiliza para respetar estos y mostrar el texto en negrita o subrayado (¡quizás todavía lo haga!) –

+0

Todavía funciona: $ echo 'h_^Hell^Hlo' | menos –

Respuesta

12

Active la opción 'pegar' (usando :set paste), y luego presione dd i <CTRL-R> 1 <ESC> en cada línea que desea aplicar los retrocesos a. Esto también funciona si elimina varias líneas, o incluso todo el archivo.

La clave aquí es que está utilizando <CTRL-R> 1 en modo de inserción a 'escribir a cabo' el contenido del registro 1 (donde sus líneas eliminadas simplemente dieron poner), y la opción de 'pegar' impide Vim el uso de cualquier asignación o abreviaciones

+1

Gracias! Grabé esto (qa) para poder aplicarlo a una línea con @a – Draemon

+1

Clever. Me gusta. –

+0

Para querer hacer varias líneas, la segunda 'd' debe cambiarse. Por ejemplo, para hacer un archivo completo de 100 líneas, coloque el cursor en la parte superior, luego 'd 100 ' – jnovack

0

Simplemente elimine todas las ocurrencias de^H (donde es la interpretación de expresiones regulares de...):

:s/.^H//g 

(inserto^H, literalmente, mediante la introducción de Ctrl-V Ctrl-H)

que la voluntad aplicar a la línea actual. Use el rango que desee si desea aplicarlo a otras líneas.

Una vez que haya realizado un comando :s..., puede repetir en otra línea simplemente escribiendo :sg (debe g al final para volver a aplicarlo a todas las instancias en la línea actual).

+0

Esto no funcionará para "algo así" como este " – Draemon

+1

Esto no "aplicar" los espacios posteriores según lo solicitado. Necesitamos eliminar los caracteres sobre los que se supone que retroceden también los^H. –

+0

¿No viste el punto en la expresión regular? Estoy de acuerdo en que no maneja una cadena de caracteres de retroceso, pero borra el carácter que tendría el retroceso. – camh

8

respuesta simplista:

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

donde ^^ H es:

  1. literal^carácter
  2. Ctrl-V Ctrl-H

y repetirlo par de veces (hasta que vim le diga que no se han realizado sustituciones

Si quieres sin repetición, y que no les importa usar% Perl:

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

Todos los personajes son literales - es decir, usted no tiene que hacer ctrl-v ... en cualquier parte por encima de la línea!.

Debería funcionar en la mayoría de los casos.

+0

Me gusta, pero me preguntaba si había una forma sin tener que repetirla (no con expresiones regulares, por supuesto) – Draemon

+0

Claro, aquí lo tiene :) –

+0

'[^^ H]' no parece correcto. ¿No coincidirá con ningún personaje que no sea '^' ni 'H'? Algo más parecido a '[. \ A] (? eyelidlessness

0

¿Qué le parece la función siguiente? He usado \% x08 en lugar de^H, ya que es más fácil copiar y pegar el código resultante. Usted puede escribir en y utilizar Ctrl - VCtrl - H si lo prefiere, pero pensé \ x08% podría ser más sencillo. Esto también intenta manejar espacios vacíos al comienzo de la línea (simplemente los elimina).

" 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 

uso con:

" Whole file: 
:ApplyBackspaces 
" Whole file (explicitly requested): 
:%ApplyBackspaces 
" Visual range: 
:'<,'>ApplyBackspaces 

Para obtener más información, véase:

:help command 
:help command-range 
:help function 
:help function-range-example 
:help substitute() 
:help =~ 
:help \%x 

Editar

Tenga en cuenta que si quieres trabajar en una sola línea que, podría hacer algo como esto:

" 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> 

o usted podría hacer:

nmap ,b :.ApplyBackspaces<CR> 
1

bien, aquí es una solución de metal desnudo.

Copia este código en un archivo llamado 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); 
} 

compilar este código con su compilador favorito:

gcc crush.c -o crush 

Entonces utilizar de esta manera para aplastar a cabo esas secuencias molestos:

./crush <infilename >outfilename 

O úselo en una tubería ("decir" es una aplicación de voz a texto en la Mac)

man date | ./crush | say 

Puede copiar aplastar a su directorio favorito ejecutable (/ usr/local/bin, o algo así) y luego hacer referencia a ella de la siguiente manera

man date | crush | say 
8

Googled esto mientras intenta recordar el comando Había usado antes para 'aplicar' espacios en blanco, y luego lo recordaba: col -b - aquí está el manpage. (Se hace un poco más y viene de BSD o más exactamente en & T UNIX como dice la página de manual, por lo que si usted está en Linux puede que tenga que instalar un paquete adicional, en debian su en bsdmainutils.)

+0

eres un dios !!! – JeffG

+0

ganas el hilo :) – Joe

0

aquí está un filtro basado en Bash puede utilizar para procesar el archivo completo:

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

Tenga en cuenta que donde aparece ^h, se entró en vim utilizando CTRL-V Ctrl-h, y la ^^ h se ingresa como SHIFT-6 CTRL-v CTRL-h.

0

Aquí hay un filtro Awk mucho más rápido que hace lo mismo:

#!/usr/bin/awk -f 
function crushify(data) { 
    while (data ~ /[^^H]^H/) { 
     gsub(/[^^H]^H/, "", data) 
    }              
    print data 
} 

crushify($0) 

Tenga en cuenta que donde aparece ^^ H, el primer símbolo de intercalación en ^^ H es un símbolo de intercalación (shift-6) y el segundo símbolo de intercalación con H se ingresa (en vim) al escribir CTRL-v CTRL-H

Cuestiones relacionadas