2009-08-19 10 views
10

J'ai un fichier journal avec des caractères de retour arrière (^ H). Je regarde le fichier dans Vim et il peut être assez difficile de voir ce qui se passe.Comment "appliquer" des caractères de retour arrière dans un fichier texte (idéalement dans vim)

Idéalement, j'aimerais pouvoir "appliquer" tout le^H sur une ligne/gamme donnée afin que je puisse voir le résultat final.

Je préférerais faire cela dans Vim ligne par ligne, mais une solution qui convertit tout le fichier vaut mieux que rien.

+0

Par curiosité, quel est le but des caractères^H?Que sont-ils destinés à réaliser, soit sur une impression, soit sur la console? –

+0

@ John Saunders: Sur les imprimantes à l'ancienne, ils ont causé une surimpression qui vous a permis de faire gras par répétition: x^Hx^Hx^Hx ou souligner: _^Ha_^Hb_^Hc. "moins" sur Linux utilisé pour les respecter et afficher le texte en gras ou souligné (peut-être qu'il le fait toujours!) –

+0

Cela fonctionne toujours: $ echo 'h_^Hell^Hlo' | moins –

Répondre

12

Activez l'option « paste » (en utilisant :set paste), puis appuyez sur dd i <CTRL-R> 1 <ESC> sur chaque ligne que vous souhaitez appliquer les backspaces à. Cela fonctionne également si vous supprimez plusieurs lignes, ou même le fichier entier.

La clé ici est que vous utilisez <CTRL-R> 1 en mode d'insertion à l'option « taper » le contenu du registre 1 (où vos lignes supprimées viennent de se mettre), et « coller » empêche Vim d'utiliser des applications ou abréviations.

+1

Merci! J'ai enregistré ceci (qa) ainsi je peux l'appliquer à une ligne avec @a – Draemon

+1

Clever. J'aime ça. –

+0

Pour vouloir faire plusieurs lignes, le second 'd' devrait être changé. Par exemple, pour faire un fichier entier de 100 lignes, placez votre curseur en haut, puis 'd 100 ' – jnovack

0

Il suffit de supprimer toutes les occurrences de^H (où est l'interprétation de regex..).

:s/.^H//g 

(insert^H littéralement en entrant Ctrl-V Ctrl-H)

qui appliquer à la ligne actuelle. Utilisez la plage que vous voulez si vous souhaitez l'appliquer à d'autres lignes.

Une fois que vous avez exécuté une commande :s..., vous pouvez répéter sur une autre ligne en tapant simplement :sg (vous devez ajouter g à la fin pour appliquer à nouveau toutes les occurrences de la ligne en cours).

+0

Cela ne fonctionnera pas pour "somethadr^h^h^hing comme ceci" – Draemon

+1

Ce ne sera pas "appliquer" les backspaces comme demandé. Nous devons supprimer les caractères que le^H est supposé faire revenir en arrière. –

+0

N'avez-vous pas vu le point dans la regex? Je suis d'accord qu'il ne gère pas une chaîne de caractères de retour arrière, mais il supprime le caractère que le retour arrière aurait. – camh

8

réponse Simplistic:

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

où ^^ H est:

  1. caractère^caractère
  2. Ctrl-V Ctrl-H

et répéter deux fois (jusqu'à ce que vim vous dise qu'aucune substitution n'a été faite

Si vous voulez sans répétition, et ne vous dérange pas en utilisant% perl:

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

Tous les caractères sont littéralement - dire que vous ne devez pas faire ctrl-v ... partout dans la ligne ci-dessus!.

Devrait fonctionner dans la plupart des cas.

+0

Je l'aime, mais je me demandais s'il y avait un moyen sans avoir à le répéter (pas avec regex bien sûr) – Draemon

+0

Bien sûr, ici vous l'avez :) –

+0

'[^^ H]' ne semble pas correct. Ne correspondra-t-il pas à un caractère qui n'est ni '^' ni 'H'? Quelque chose de plus comme '[. \ A] (? eyelidlessness

0

Que diriez-vous de la fonction suivante? J'ai utilisé \% x08 au lieu de^H car il est plus facile de copier et coller le code résultant. Vous pouvez taper et utiliser Ctrl - VCtrl - H si vous préférez, mais je pensais que \% x08 pourrait être plus facile. Cela tente également de gérer les backspaces au début de la ligne (il suffit de les supprimer).

" 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 

Utilisation avec:

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

Pour plus d'informations, voir:

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

Modifier

Notez que si vous voulez travailler sur une seule ligne, pourrait faire quelque chose comme ceci:

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

ou vous pouvez simplement faire:

nmap ,b :.ApplyBackspaces<CR> 
1

D'accord, voici une solution en métal nu.

Copiez ce code dans un fichier nommé 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); 
} 

Compile ce code avec votre compilateur préféré:

gcc crush.c -o crush 

utiliser ensuite comme ceci pour écraser ces séquences gênantes:

Ou utilisez-le dans un pipeline ("dites" est une application de la parole au texte sur le Mac)
./crush <infilename >outfilename 
man date | ./crush | say 

Vous pouvez copier écraser dans votre répertoire exécutable préféré (/ usr/local/bin, ou quelque), puis référence comme suit

man date | crush | say 
8

Je googlé cela tout en essayant de se rappeler la commande Je l'avais déjà utilisé pour appliquer des backspaces, puis je m'en suis souvenu: col -b - voici le manpage. (Il fait un peu plus et vient de BSD ou plus exactement AT & T UNIX comme dit manpage, donc si vous êtes sur Linux vous devez installer un paquet supplémentaire, sur debian son dans bsdmainutils.)

+0

vous êtes un dieu !!! – JeffG

+0

vous gagnez le fil :) – Joe

0

Voici un filtre basé Bash vous pouvez utiliser pour traiter le fichier entier:

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

Notez que lorsque ^h apparaît, il est entré dans vim en utilisant CTRL-v CTRL-h, et le ^^ h est entré en tant que SHIFT-6 CTRL-v CTRL-h.

0

est ici un filtre Awk beaucoup plus rapide qui fait la même:

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

crushify($0) 

Notez que lorsque ^^ H apparaît, la première caret dans ^^ H est un caret (shift-6) et le deuxième signe avec H est entré (dans vim) en tapant CTRL-v CTRL-H

Questions connexes