Entfernen Sie unbekannte Unicode-Zeichen aus Textdateien - sed, andere Bash / Shell-Methoden

9

Ich muss alle Vorkommen eines unbekannten Zeichens in einigen Dateien mit demselben Namen suchen und ersetzen.

Wenn ich solche Dateien mit vi öffne, lese ich den <91> -Code für dieses Zeichen. Ich öffnete sie mit Nano und las ein "Fragezeichen" in einem Diamanten (schwarzes Rhumble).

Ich möchte solch ein unbekanntes Zeichen durch ein Zitat (') ersetzen. Ich versuche viele Wege ohne Glück.

Ich habe es versucht:

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



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

BEARBEITEN Weitere Informationen zum Charakter:

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

Wenn Sie mehr brauchen, fragen Sie!

Jasmin
quelle
Inwiefern funktioniert sed -i "s/\x91/'/g"das filenicht?
Stéphane Chazelas

Antworten:

3

Sie sollten einen Blick darauf werfen hexdump -Cund die Bytes um ihn herum finden. Vorausgesetzt , UTF-8, was vizeigt , wie <91>(dezimal 145, ein Unicode - Punkt bedeutungslos im Text) würde zwei Bytes, 0xC2 und 0x91.

Es ist impliziert, dass Ihre Ersetzungen überhaupt nicht funktioniert haben, aber wenn Sie nur 0x91 durch 0x27 ersetzt haben, haben Sie den UTF-8 ungültig gemacht (für das zweite Byte einer Zwei-Byte-Sequenz ist immer das High-Bit gesetzt, dh > = 0x80). Dies könnte Ihre Analyse erschweren, visollte sie dann aber als anzeigen ?'.

Das heißt, ich habe dies getestet und es funktioniert:

#!/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;  

Wenn $ARGV[0]vorhanden <>ist, wenn darauf verwiesen wird, entfernt Perl dies vom Argumentstapel und verwendet es als Dateipfad für die Eingabe (ich finde kurze Skripte einfacher zu optimieren und zu bearbeiten als ein Liner, übrigens). Dies sammelt sich im Speicher an (in Ordnung, solange die Dateien nicht massiv sind), während perl -idie Originaldatei umbenannt wird, um zu vermeiden, dass die Rennbedingungen vor Ort bearbeitet werden (siehe perldoc perlrun).

Das könnten Sie also nutzen:

  find . -name "*.txt" -exec whatever.pl {} +
Goldlöckchen
quelle
es funktioniert nicht, das Fragezeichen bleibt ...
Jasmin
Hast du es eingecheckt, um hexdump -Czu sehen, was tatsächlich da ist?
Goldlöckchen
3

Wenn es sich tatsächlich um das Zeichen U + 0091 (0xc2 0x91 in UTF-8-Codierung) und nicht um das Byte 0x91 handelt, dann:

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

Würde es konvertieren zu '.

Mit GNU sed:

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

Bearbeiten:

In Ihrem Fall befindet sich die Datei jedoch nicht in UTF-8. UTF-8-Zeichen sind ein Byte, nur für ASCII-Zeichen (für Werte 0 bis 0x7F). Die anderen Zeichen werden durch zwei oder mehr Bytes dargestellt, deren Wert größer als ist 0x7F. Ein 0x91Byte, um das kein Byte größer als 0x7F ist, kann also nicht in einer utf-8-Datei gefunden werden.

Wahrscheinlicher ist, dass sich Ihre Datei in einem Einzelbyte-Zeichensatz befindet, höchstwahrscheinlich in einem Microsoft-Zeichensatz wie Windows-1252 .

In Windows 1252 ist 0x91 das linke einfache Anführungszeichen. Das Unicode-Äquivalent ist U + 2018, das in UTF-8 geschrieben ist 0xe2 0x80 0x98.

Wenn Sie Ihre Datei in UTF-8 konvertieren möchten, ist es wahrscheinlich am besten, ein spezielles Tool dafür zu verwenden. Mögen:

recode windows-1252..utf8 < file

Oder:

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

Oder wenn Sie es für jeden tun möchten 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
quelle
es funktioniert nicht, das Fragezeichen bleibt ...
Jasmin
@jasmines Dann ist es nicht ein U+0091. Bitte fügen Sie die Ausgabe von LC_ALL=C sed -n l < filezur Frage hinzu.
Stéphane Chazelas
es scheint \ 221
Jasmin
Ich kann nicht konvertieren, da es sich nicht um eine einzelne Datei handelt. Ich muss stapelweise und rekursiv suchen und ersetzen.
Jasmin