Bin grade bei der Portierung von C Code von Unix auf Win 10 auf den mir
bis dahin völlig unbekannten Byte Order Mark gestossen:
https://de.wikipedia.org/wiki/Byte_Order_Mark
Bei einer Datei mit einer Zahl zum Einlesen drin, die im Notepad noch
normal aussieht, zeigt der HEX-Editor am Anfang extra:
EF BB BF
Das soll die UTF-8 Kennung sein.
Ich habe das Problem jetzt erst mal mit dem Holzhammer gelöst, damit es
auf Unix und Win 10 läuft. Geht es noch anders?
while (true)
{
int num = fgetc(fp);
if (num == EOF)
{
str[idx] = 0;
break;
}
if (('0' <= num) && (num <= '9'))
str[idx++] = (char) num;
}
Wenn in der Datei eh nur Ziffern drin sein sollen, geht das so.
Bei denen unterscheiden sich die Binärdaten nicht, egal ob ASCII
codiert, MS Windows mit Codepage 1252 codiert, ISO 8859-1 codiert, ISO
8859-15 codiert, MS DOS mit Codepage 437 oder 850 codiert, UTF8 auf
einem System mit Little Endian oder UTF8 auf einem System mit Big Endian
codiert.
Die Byte Order Mark oder kurz nur BOM ist dafür gedacht, bei UTF8 zu
erkennen, in welcher Reihenfolge 16-bittige Codes abgelegt wurden.
Nebenbei hilft sie natürlich auch UTF8 schnell und einfach zu erkennen.
Aber da die Codes für Ziffern alle 8-bittig sind, kann Dir das egal
sein.
Mit Deinem Code würdest Du sogar Tausendertrennzeichen oder Leerzeichen,
die jemand zur besseren Lesbarkeit für Menschen eingefügt hat abkönnen.
Sollte natürlich mal die Datei zerschossen sein, bastelt der Code halt
eine Zahl draus ohne jegliche Warnung.
Kommt halt drauf an, was sonst noch in der Datei steht das du auslesen
möchtest und welche Mittel dir im Code zur Verfügung stehen.
Die nächst-aufwendigere Stufe wäre imho eine Regex. Damit lassen sich
auch Kommentare o.ä. leicht in das Dateiformat integrieren.
Noch aufwendiger wäre ein richtiger Parser mit Grammatik. Es würde mich
aber wundern, wenn sich das lohnt.
Lothar schrieb:> Geht es noch anders?
Sicher.
Der elegante Weg ist ein eigenes fgetc.
Das liest ein ASCII Zeichen, wandelt die mit gesetztem high bit vom
lokalen Zeichensatz in Unicode, und gibt es zurück.
Wenn jedoch am Dateianfang (ftell(f)==0) eine BOM stand, ändert es
seinen Lesemodus und sammelt es UTF8 Zeichen bis das Unicode-Zeichen
komplett ist und liefert dann das.
Stand am Dateianfang ein UTF16 oder UTF32 BOM liest es jene in passender
Byteorder.
Dabei muss es nicht nur -1 für Dateiende sondern auch 0xFFFD liefern
wenn eine ungültige Zeichenfolge gefunden wurde
So kannst du jede Datei korrekt lesen. Die eine Funktion taugt für
immer.
FOp schrieb:> Die Byte Order Mark oder kurz nur BOM ist dafür gedacht, bei UTF8 zu> erkennen, in welcher Reihenfolge 16-bittige Codes abgelegt wurden.> Nebenbei hilft sie natürlich auch UTF8 schnell und einfach zu erkennen.> Aber da die Codes für Ziffern alle 8-bittig sind, kann Dir das egal> sein.
Nein, BOM ist bei UTF-8 immer EF BB BF. UTF-8 hat kein Problem mit der
Byteorder (Little- vs. Bigendian) wie UTF-16 oder UTF-32. Mann erkennt
am BOM nur mit hoher Wahrscheinlichkeit eine UTF-8 codierte Textdatei.
https://de.wikipedia.org/wiki/Byte_Order_Mark
Matthias
Lothar schrieb:> Ich habe das Problem jetzt erst mal mit dem Holzhammer gelöst, damit es> auf Unix und Win 10 läuft. Geht es noch anders?
Sobald etwas anderes als ASCII in deiner (UTF8)Datei steht, wird der
Holzhammer aber einen dicken, roten Daumen produzieren.
Unter Linux würde ich für so etwas eventuell Funktionen aus der libidn
benutzen.
›stringprep_utf8_to_locale(…)‹
Convert string encoded in UTF-8 into the locale's character set by
using stringprep_convert().
Womöglich gibt es so etwas auch für Windows.
Der UTF-8 BOM ist optional. Ich würde diesen, wenn immer möglich, weg
lassen.
Auf modernen Linux Systemen verwendet heutzutage eigentlich jeder utf-8.
GUI Toolkits können in der Regel problemlos damit umgehen, die locale in
C auch.
Bei meinen C Programmen gehe ich mittlerweile einfach davon aus, das
utf8 verwendet wird. Wobei das meistens gar keinen unterschied macht.
UTF-8 ist Rückwärtskompatibel zu ASCII. Die Bytes von nicht-ASCII
Zeichen sind immer grösser als 127/0x1F, also ausserhalb des ASCII
Bereichs. Nach einem Bytewert für ein ASCII Zeichen zu suchen ist also
weiterhin sicher. Null Bytes kommen darin auch keine vor. Auch die
Sortierung nach Bytewerten führt weiterhin nach einer korrekten
Sortierung nach Codepunkten. Ein Programm, das mit ASCII zurecht kommt,
kommt also auch mit utf8 zurecht. Nur eben der optionale BOM kann
manchmal Probleme machen. Dessen Verwendung ist auch nicht empfohlen.
Windows verwendet halt gerne intern aber UTF-16, oder dieses
fast-UTF-16. Und Windows Programme verwenden gerne Sachen wie z.B.
wchar_t oder wchar16_t. Deshalb hat man bei Windows Sachen viel eher
Probleme, als mit Unicode. UTF-8 geht normalerweise einfach, ohne
weiteres zutuen, da Rückwärtskompatibel usw. Aber mit dem UTF-16 Zeugs
und den BOMs usw., das fällt einem bei Windows dann halt dann um die
Ohren.
Μαtthias W. schrieb:> Nein, BOM ist bei UTF-8 immer EF BB BF. UTF-8 hat kein Problem mit der> Byteorder (Little- vs. Bigendian) wie UTF-16 oder UTF-32.
Das ist nur halb richtig. Der UTF-8, sowie die beiden UTF-16 BOMs, haben
einen Unicode Codepoint / Wert, und dieser ist jeweils nicht der selbe!
Deshalb kann ein UTF-16 BOM als UTF-8 Sequenz kodiert werden. Das ist
für nichts gut, ausser um Probleme zu verursachen, aber es ist machbar.
U+FFFE ist EF BF BE. Und U+FEFF ist EF BB BF.
DPA schrieb:> Windows verwendet halt gerne intern aber UTF-16, oder dieses> fast-UTF-16. Und Windows Programme verwenden gerne Sachen wie z.B.> wchar_t oder wchar16_t. Deshalb hat man bei Windows Sachen viel eher> Probleme, als mit Unicode. UTF-8 geht normalerweise einfach, ohne> weiteres zutuen, da Rückwärtskompatibel usw. Aber mit dem UTF-16 Zeugs> und den BOMs usw., das fällt einem bei Windows dann halt dann um die> Ohren.
Das ist historisch begründet; das tut nämlich ernstgemeintes Windows
schon seit bald 30 Jahren, und da war an UTF-8 oder dergleichen noch
sehr, sehr lange nicht zu denken. Die damals gewählte Implementierung
(UCS-2, einfach nur "Unicode" genannt) verwendete konstante 16 Bit pro
Zeichen, was die Abbildung auf Funktionen wie strcpy/strlen etc. sehr
einfach machte.
DerEgon schrieb:> Die damals gewählte Implementierung> (UCS-2, einfach nur "Unicode" genannt) verwendete konstante 16 Bit pro> Zeichen, was die Abbildung auf Funktionen wie strcpy/strlen etc. sehr> einfach machte.
Nur der Vollständigkeit halber war es mit Einführung der Surrogate-Bytes
dann auch mit der Einfachheit vorbei.
Wobei ich trotzdem lieber UTF-16 als UTF-8 verwende.
loeti2 schrieb:> Wobei ich trotzdem lieber UTF-16 als UTF-8 verwende
Da habe ich doch gar keinen Einfluss drauf.
Wenn ich unter Win 10 den Notepad aufmache, was schreibe, und speichere,
wird es UTF-8
Lothar schrieb:> Da habe ich doch gar keinen Einfluss drauf.
Doch, hast du.
> Wenn ich unter Win 10 den Notepad aufmache, was schreibe, und speichere,> wird es UTF-8
Das kannst du ändern. Wenn du nicht vollkommen verblödet bist...
Der Notepad von Windows10 ist zwar immer noch ein eher armseliger
Texteditor, aber Encodings hat er durchaus drauf. Wie das gesamte
Windows-System...
Gegen völlig inkompetente Benutzer ist er aber, wie jede andere Software
auch, vollkommen machtlos...