Ich muss beschädigte Textdateien erkennen, in denen ungültige (Nicht-ASCII-) utf-8-, Unicode- oder binäre Zeichen vorhanden sind.
�>t�ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½w�ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½o��������ï¿ï¿½_��������������������o����������������������￿����ß����������ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½~�ï¿ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½}���������}w��׿��������������������������������������ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½~������������������������������������_������������������������������������������������������������������������������^����ï¿ï¿½s�����������������������������?�������������ï¿ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½w�������������ï¿ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½}����������ï¿ï¿½ï¿½ï¿½ï¿½y����������������ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½o�������������������������}��
was ich versucht habe:
iconv -f utf-8 -t utf-8 -c file.csv
dadurch wird eine Datei von der utf-8-Codierung in die utf-8-Codierung konvertiert, und -c
dient zum Überspringen ungültiger utf-8-Zeichen. Am Ende wurden diese illegalen Zeichen jedoch noch gedruckt. Gibt es andere Lösungen in bash für Linux oder andere Sprachen?
Angenommen, Sie haben das Gebietsschema auf UTF-8 gesetzt. Dies funktioniert gut, um ungültige UTF-8-Sequenzen zu erkennen:
grep -axv '.*' file.txt
Ich würde grep
für nicht ASCII Zeichen.
Mit GNU grep mit pcre (wegen -P
, nicht immer verfügbar. Unter FreeBSD können Sie pcregrep im Paket pcre2 verwenden):
grep -P "[\x80-\xFF]" file
Referenz in Wie grep ich für alle Nicht-ASCII-Zeichen in UNIX . Wenn Sie also nur prüfen möchten, ob die Datei keine ASCII -Zeichen enthält, können Sie einfach sagen:
if grep -qP "[\x80-\xFF]" file ; then echo "file contains ascii"; fi
# ^
# silent grep
Um diese Zeichen zu entfernen, können Sie Folgendes verwenden:
sed -i.bak 's/[\d128-\d255]//g' file
Dadurch wird eine file.bak
-Datei als Sicherungskopie erstellt, während für die ursprüngliche file
keine Zeichen ASCII entfernt werden. Referenz in Nicht-ASCII-Zeichen aus csv entfernen.
Was Sie betrachten, ist per Definition beschädigt. Anscheinend zeigen Sie die Datei so an, wie sie in Latin-1 dargestellt wird. die drei Zeichen stehen für die drei Byte-Werte 0xEF 0xBF 0xBD. Dies ist jedoch die UTF-8-Kodierung des Unicode REPLACEMENT CHARACTER U + FFFD , die das Ergebnis des Versuchs ist, Bytes einer unbekannten oder undefinierten Kodierung in UTF-8 zu konvertieren, und die ordnungsgemäß als angezeigt würde (wenn Wenn Sie einen Browser aus diesem Jahrhundert haben, sollten Sie so etwas wie einen schwarzen Diamanten mit einem Fragezeichen darin sehen; dies hängt jedoch auch von der verwendeten Schriftart ab.
Daher ist Ihre Frage nach dem "Erkennen" dieses speziellen Phänomens einfach; Der Unicode-Codepunkt U + FFFD ist ein totes Giveaway und das einzig mögliche Symptom des von Ihnen implizierten Prozesses.
Dies sind nicht "ungültiger Unicode" oder "ungültiger UTF-8" in dem Sinne, dass dies eine gültige UTF-8-Sequenz ist, die einen gültigen Unicode-Codepunkt codiert. Es ist nur so, dass die Semantik dieses speziellen Codepunkts lautet: "Dies ist ein Ersatzzeichen für ein Zeichen, das nicht richtig dargestellt werden konnte", d. h. eine ungültige Eingabe.
Um dies zu verhindern, ist die Antwort wirklich einfach, aber auch wenig informativ. Sie müssen feststellen, wann und wie die falsche Kodierung stattgefunden hat, und den Prozess korrigieren, der zu dieser ungültigen Ausgabe geführt hat.
Um die U + FFFD-Zeichen einfach zu entfernen, versuchen Sie etwas wie
Perl -CSD -pe 's/\x{FFFD}//g' file
aber auch hier ist es die richtige Lösung, diese fehlerhaften Ausgaben gar nicht erst zu erzeugen.
(Sie offenbaren nicht die Kodierung Ihrer Beispieldaten. Es ist möglich, dass sie eine zusätzliche - Beschädigung aufweist. Wenn Sie uns eine Kopie des UTF-8-Rendering der Daten zeigen, war dies der Fall "double-encoded". Mit anderen Worten, jemand nahm UTF-8-Text an, der bereits wie oben beschrieben beschädigt war, und forderte den Computer auf, ihn von Latin-1 nach UTF-8 zu konvertieren. Das Rückgängigmachen ist einfach; konvertieren Sie einfach es "zurück" zu Latin-1. Was Sie erhalten sollten, sind die ursprünglichen UTF-8-Daten vor der überflüssigen fehlerhaften Konvertierung.)
Dieses Perl-Programm sollte alle Nicht-ASCII-Zeichen entfernen:
foreach $file (@ARGV) {
open(IN, $file);
open(OUT, "> super-temporary-utf8-replacement-file-which-should-never-be-used-EVER");
while (<IN>) {
s/[^[:ascii:]]//g;
print OUT "$_";
}
rename "super-temporary-utf8-replacement-file-which-should-never-be-used-EVER", $file;
}
Was dies bedeutet, ist, dass Dateien als Eingabe in die Befehlszeile verwendet werden, wie dies z.
Perl fixutf8.pl foo bar baz
Dann ersetzt es für jede Zeile jede Instanz eines Nicht-ASCII-Zeichens durch nichts (Löschen).
.__ Diese Zeile wird dann in super-temporary-utf8-replacement-file-which-should-never-be-used-EVER
geschrieben (so benannt, dass keine anderen Dateien geändert werden.)
Anschließend wird die temporäre Datei in die der ursprünglichen Datei umbenannt.
Dies akzeptiert ALLE ASCII -Zeichen (einschließlich DEL, NUL, CR usw.), falls Sie eine spezielle Verwendung haben. Wenn Sie nur druckbare Zeichen wünschen, ersetzen Sie einfach :ascii:
durch :print:
in s///
.
Ich hoffe das hilft! Bitte lassen Sie mich wissen, ob Sie nicht danach gesucht haben.
Ich wiederhole wahrscheinlich, was andere schon gesagt haben. Aber ich denke, Ihre ungültig-Zeichen werden noch gedruckt, da sie möglicherweise gültig sind. Der Universal Character Set ist der Versuch, auf die weltweit häufig verwendeten Zeichen zu verweisen, um robuste Software schreiben zu können, die nicht auf einen speziellen Zeichensatz angewiesen ist.
Ich denke, Ihr Problem könnte eines der beiden sein - in der Annahme, dass Ihr allgemeines Ziel darin besteht, diese (böswilligen) Eingaben aus utf-Dateien im Allgemeinen zu behandeln:
Meines Erachtens haben Sie zwei Möglichkeiten, um damit umzugehen:
iconv -f utf-8 -t ascii -o file_in_ascii.txt file_in_utf8.txt
. Seien Sie jedoch vorsichtig, wenn der breitere Zeichenbereich (utf) in einen kleineren übertragen wird, was zu Datenverlust führen kann.Der Umgang mit utf mag schwierig erscheinen, die folgenden Schritte können Ihnen dabei helfen, utf-Readyness zu erreichen:
uconv
vorschlägt, die Sie verwenden können um einen Callback-Handler für ungültige Sequenzen festzulegen.Eine sehr schmutzige Lösung in Python 3
import sys
with open ("cur.txt","r",encoding="utf-8") as f:
for i in f:
for c in i:
if(ord(c)<128):
print(c,end="")
Die Ausgabe sollte sein:
>two_o~}}w~_^s?w}yo}
Das folgende C-Programm erkennt ungültige utf8-Zeichen . Es wurde getestet und auf einem Linux-System verwendet.
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
void usage( void ) {
printf( "Usage: test_utf8 file ...\n" );
return;
}
int line_number = 1;
int char_number = 1;
char *file_name = NULL;
void inv_char( void ) {
printf( "%s: line : %d - char %d\n", file_name, line_number, char_number );
return;
}
int main( int argc, char *argv[]) {
FILE *out = NULL;
FILE *fh = NULL;
// printf( "argc: %d\n", argc );
if( argc < 2 ) {
usage();
exit( 1 );
}
// printf( "File: %s\n", argv[1] );
file_name = argv[1];
fh = fopen( file_name, "rb" );
if( ! fh ) {
printf( "Could not open file '%s'\n", file_name );
exit( 1 );
}
int utf8_type = 1;
int utf8_1 = 0;
int utf8_2 = 0;
int utf8_3 = 0;
int utf8_4 = 0;
int byte_count = 0;
int expected_byte_count = 0;
int cin = fgetc( fh );
while( ! feof( fh ) ) {
switch( utf8_type ) {
case 1:
if( (cin & 0x80) ) {
if( (cin & 0xe0) == 0xc0 ) {
utf8_1 = cin;
utf8_type = 2;
byte_count = 1;
expected_byte_count = 2;
break;
}
if( (cin & 0xf0) == 0xe0 ) {
utf8_1 = cin;
utf8_type = 2;
byte_count = 1;
expected_byte_count = 3;
break;
}
if( (cin & 0xf8) == 0xf0 ) {
utf8_1 = cin;
utf8_type = 2;
byte_count = 1;
expected_byte_count = 4;
break;
}
inv_char();
utf8_type = 1;
break;
}
break;
case 2:
case 3:
case 4:
// printf( "utf8_type - %d\n", utf8_type );
// printf( "%c - %02x\n", cin, cin );
if( (cin & 0xc0) == 0x80 ) {
if( utf8_type == expected_byte_count ) {
utf8_type = 1;
break;
}
byte_count = utf8_type;
utf8_type++;
if( utf8_type == 5 ) {
utf8_type = 1;
}
break;
}
inv_char();
utf8_type = 1;
break;
default:
inv_char();
utf8_type = 1;
break;
}
if( cin == '\n' ) {
line_number ++;
char_number = 0;
}
if( out != NULL ) {
fputc( cin, out );
}
// printf( "lno: %d\n", line_number );
cin = fgetc( fh );
char_number++;
}
fclose( fh );
return 0;
}
Versuchen Sie dies, um Nicht-ASCII-Zeichen in der Shell zu finden.
Befehl:
$ Perl -ne 'print "$. $_" if m/[\x80-\xFF]/' utf8.txt
Ausgabe:
2 Pour être ou ne pas être
4 Byť či nebyť
5 是或不