Remove caracteres unicode desconhecidos de arquivos de texto - sed, outros métodos bash / shell

9

Eu preciso pesquisar e substituir todas as ocorrências de um caractere desconhecido em alguns arquivos com o mesmo nome.

Abrindo esses arquivos com o vi, eu leio < 91 > código para esse caractere. Abrindo-os com nano, eu li um "ponto de interrogação" em um diamante (black rhumble).

Eu gostaria de substituir esse caractere desconhecido por uma citação ('). Estou tentando de muitas maneiras sem sorte.

Eu tentei:

find ./ -name filename.txt -exec perl -i~ -pe "s/\x91/'/" {} \;



find ./ -name filename.txt -exec sed -i "s/\x91/'/g" {} \;

EDITAR Mais informações sobre o personagem:

Hexadecimal: 91 68 74 74
Decimal: 145 104 116 116
Octal: 221 150 164 164
Binary: 10010001 01101000 01110100 01110100

LC_ALL=C sed -n l < file

1

Se precisar de mais, pergunte!

    
por jasmines 20.02.2014 / 16:40

2 respostas

3

Você deve dar uma olhada usando hexdump -C e encontrar os bytes em torno dele. Presumindo UTF-8, o que vi mostra como <91> (decimal 145, um ponto unicode sem significado no texto) seria dois bytes, 0xc2 e 0x91.

Está implícito que suas substituições não funcionaram, mas se o que você fez foi apenas substituir 0x91 por 0x27, você invalidará o UTF-8 (o segundo byte de uma sequência de dois bytes sempre terá o bit alto configurado , ou seja, é > = 0x80). Isso pode complicar sua análise, embora vi deva mostrá-la como ?' .

Dito isto, testei isto e funciona:

#!/usr/bin/perl
use strict;
use warnings FATAL => qw(all);

my $data = "";
my $file = $ARGV[0];

while (<>) {
    s/\xc2\x91/'/g;
    $data .= $_;
}

open my $out, '>', $file || die "Could not write $file.";
print $out $data;
close $out;  

Se $ARGV[0] existe quando <> é referenciado, perl extrai isso da pilha de argumentos e o usa como um caminho de arquivo para usar (acho que scripts curtos são mais fáceis de ajustar e trabalhar com um forro, BTW). Isso se acumula na memória (bem, desde que os arquivos não sejam grandes), enquanto perl -i renomeia o arquivo original para evitar condições de corrida edit-in-place (veja perldoc perlrun ).

Então você pode usar isso:

  find . -name "*.txt" -exec whatever.pl {} +
    
por 20.02.2014 / 17:24
3

Se for realmente o caractere U + 0091 (0xc2 0x91 na codificação UTF-8) e não o byte 0x91, então:

PERLIO=:utf8 perl -pi -e "s/\N{U+0091}/'/g" file

O converteria em ' .

Com o GNU sed :

sed -i "s/\xc2\x91/'/" file

Editar:

No entanto, no seu caso, o arquivo não está em UTF-8. Os caracteres UTF-8 são de um byte, apenas para caracteres ASCII (para valores de 0 a 0x7F). Os outros caracteres são representados por dois ou mais bytes cujo valor é maior que 0x7F . Portanto, um 0x91 byte, sem um byte maior que 0x7F, não pode ser encontrado em um arquivo utf-8.

É mais provável que seu arquivo esteja em um conjunto de caracteres de um único byte, provavelmente um pouco da Microsoft como windows-1252 .

No Windows-1252, 0x91 é o caractere de aspas simples à esquerda. O equivalente unicode é U + 2018, que em UTF-8 está escrito 0xe2 0x80 0x98 .

Se você quiser converter seu arquivo para UTF-8, provavelmente é melhor usar uma ferramenta dedicada para isso. Como:

recode windows-1252..utf8 < file

Ou:

iconv -f windows-1252 -t utf-8 < file

Ou se você quiser fazer isso para cada filename.txt :

find . -type f -name filename.txt -exec sh -Cc '
  for file do
    mv "$file" "$file~" &&
      iconv -f windows-1252 -t utf-8 < "$file~" > "$file"
  done' sh {} +
    
por 20.02.2014 / 17:55