Substituindo caracteres não imprimíveis por valores numéricos hexadecimais

0

Eu tenho um arquivo Sqlite mal corrompido O truque comum de despejar tudo em um arquivo sql e carregá-lo em um arquivo novo não funciona, mas com um editor hexadecimal eu posso ver que os dados que preciso restaurar estão lá

me deparei com este modo

Can vim exibe somente caracteres ASCII e trata outros bytes como dados binários?

para o vi exibir caracteres não imprimíveis como hexadecimal

O que é ótimo e me mostrará

‹14› ‹07› Mr Testy McTesterson [email protected]

mas existe alguma maneira de escrever isso para arquivar como é exibido?

Então, pegue o valor hexadecimal que o vi exibe como ‹14› em seu buffer e realmente o alterou para ser esses caracteres em um arquivo de texto

Eu posso fazer uma pesquisa de regex substituir no vi para fazer isso, mas então eu tenho que fazer isso para cada caractere não imprimível, um de cada vez, e é um arquivo muito grande

Mais tarde, planejo processar o ‹14› ‹07› para o inteiro de 16 bits que ele deve representar, mas primeiro eu preciso poder obtê-los como caracteres reais em um arquivo de texto

Muito obrigado antecipadamente

    
por user28226 30.06.2018 / 09:55

1 resposta

1

Você pode ver xxd , que vem com vim , e despeja dados em caracteres hexadecimais e imprimíveis em colunas. Se você editar o hexadecimal, poderá enviar os dados de volta por xxd -r para convertê-los novamente em binário.

No entanto, olhando para o seu objetivo final, você provavelmente precisará de algo mais poderoso como perl , no qual não sou especialista, mas você pode achar útil o seguinte:

#!/usr/bin/perl
# https://unix.stackexchange.com/a/452784/119298
use strict;
sub fn{ 
    my ($ch,$ch2,$rest) = @_;
    return sprintf("%5u",(ord($ch)<<8)|ord($ch2)).$rest;
}
my $data = join("",<>);
$data =~ s/(.)(.)([a-zA-Z][ -~]{10,})/fn($1,$2,$3)/ge;
print $data;

Ele lê todos os dados do stdin na variável $data e, em seguida, faz um substituto global ( s/.../.../g ) para o padrão consiste em quaisquer 2 bytes seguidos por um caractere alfabético (o intervalo a-z e A-Z), seguido por 10 ou mais caracteres imprimíveis (no espaço de intervalo para til e assumindo uma localidade C). Essas partes são capturadas usando () em 3 partes separadas e substituídas por uma chamada da função fn . Isso é o que significa o e no final.

A função simplesmente retorna uma seqüência de caracteres dos 2 bytes convertidos em um inteiro, concatenados com o terceiro parâmetro inalterado.

Para ajudar, aqui está uma versão mais simples que só faz o que você deseja, substituindo os caracteres não imprimíveis por <..> .

my $data = join("",<>);
$data =~ s/([^ -~\n])/sprintf("<%02x>",ord($1))/ge;
print $data;

Aqui, o padrão é mais simples, ou seja, o intervalo de caracteres não imprimíveis (e nova linha), com ^ significando não . Ao olhar para um arquivo sqlite simples, eu encontrei o caractere imediatamente antes dos dados do texto serem frequentemente um caractere imprimível. É por isso que usei um padrão que testa um caractere inicial alfabético, mas você provavelmente precisará usar uma melhor heurística.

    
por 30.06.2018 / 14:16