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.
Benutzt du ein GUI-Framework? Erst mal schauen, ob das Framework ein Paket für UTF-8 Ein-Ausgabe mitbringt.
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.
Ich habe das noch nicht allzu stark getestet, aber hier mal ein Wrapper für den TO, der UTF-8 BOMs transparent herausfiltert:
1 | #include <stdio.h> |
2 | #include <stdint.h> |
3 | |
4 | #define UTF8_BOM "\xEF\xBB\xBF"
|
5 | |
6 | struct utf8_bom_filter { |
7 | uint_least8_t match : 2; |
8 | uint_least8_t index : 2; |
9 | uint_least8_t eof : 1; |
10 | uint_least8_t next; |
11 | };
|
12 | |
13 | int bomless_fgetc(struct utf8_bom_filter*const restrict bfs, FILE*const restrict file){ |
14 | while(1){ |
15 | if(bfs->index){ |
16 | if(bfs->index < bfs->match){ |
17 | return UTF8_BOM[bfs->index++]&0xFF; |
18 | }else if(bfs->index == bfs->match){ |
19 | bfs->index = 0; |
20 | if(bfs->eof || bfs->next != (UTF8_BOM[0]&0xFF)){ |
21 | bfs->match = 0; |
22 | return bfs->eof ? EOF : bfs->next; |
23 | }else{ |
24 | bfs->match = 1; |
25 | }
|
26 | }
|
27 | }
|
28 | int ch = fgetc(file); |
29 | if((UTF8_BOM[bfs->match]&0xFF) == ch){ |
30 | if(bfs->match < 2){ |
31 | bfs->match += 1; |
32 | }else{ |
33 | bfs->match = 0; |
34 | }
|
35 | }else{ |
36 | if(bfs->match){ |
37 | bfs->next = ch; |
38 | bfs->eof = ch == EOF; |
39 | bfs->index = 1; |
40 | return UTF8_BOM[0]&0xFF; |
41 | }else{ |
42 | return ch; |
43 | }
|
44 | }
|
45 | }
|
46 | }
|
47 | |
48 | int main(){ |
49 | struct utf8_bom_filter bfs; |
50 | for(int c; (c=bomless_fgetc(&bfs, stdin)) != EOF;) |
51 | putchar(c); |
52 | }
|
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: > Wenn ich unter Win 10 den Notepad aufmache, was schreibe, und speichere, > wird es UTF-8 Nimm Notepad++ LG, Sebastian
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...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.