Remova o caractere unicode desconhecido dos arquivos de texto - sed, outros métodos bash / shell

9

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, li o código <91> para esse caractere. Abrindo-os com nano, eu li um "ponto de interrogação" em um diamante (retângulo preto).

Gostaria de substituir esse caractere desconhecido por uma citação ('). Estou tentando de várias 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" {} \;

EDIT 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

\221

Se precisar de mais, pergunte!

jasmim
fonte
De que maneira sed -i "s/\x91/'/g"isso filenão funciona?
Stéphane Chazelas

Respostas:

3

Você deve dar uma olhada usando hexdump -Ce encontrar os bytes ao seu redor. Presumindo UTF-8, o que viaparece como <91>(decimal 145, um ponto unicode sem sentido no texto) seria de dois bytes, 0xc2 e 0x91.

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

Dito isto, testei isso 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, o perl retira isso da pilha de argumentos e o usa como caminho de arquivo a ser usado para entrada (acho que scripts curtos são mais fáceis de ajustar e trabalhar com mais de um liner, BTW). Isso se acumula na memória (ótimo, desde que os arquivos não sejam enormes), enquanto perl -irenomeia o arquivo original para evitar condições de corrida de edição no local (consulte perldoc perlrun).

Então você pode usar isso:

  find . -name "*.txt" -exec whatever.pl {} +
Cachinhos Dourados
fonte
Ele não funciona, os restos ponto de interrogação ...
jasmins
Você fez check-in hexdump -Cpara ver o que realmente está lá?
GOLDILOCKS
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

Conversaria para '.

Com o GNU sed:

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

Editar:

No entanto, no seu caso, o arquivo não está no 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 0x91byte, sem byte maior que 0x7F, não pode ser encontrado em um arquivo utf-8.

O mais provável é que o arquivo esteja em um conjunto de caracteres de byte único, provavelmente em algum da Microsoft como o windows-1252 .

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

Se você deseja converter seu arquivo em UTF-8, o melhor é provavelmente usar uma ferramenta dedicada para isso. Gostar:

recode windows-1252..utf8 < file

Ou:

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

Ou se você quiser fazer isso para todos 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 {} +
Stéphane Chazelas
fonte
Ele não funciona, os restos ponto de interrogação ...
jasmins
@jasmines Então não é um U+0091. Por favor, adicione a saída de LC_ALL=C sed -n l < filepara a pergunta.
Stéphane Chazelas
parece ser \ 221
jasmines 21/02
Não consigo converter porque não é um único arquivo ... Preciso fazer um lote e pesquisar e substituir recursivamente.
JASMINES