Autor Beitrag
haschme
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 57
Erhaltene Danke: 1



BeitragVerfasst: Fr 15.07.16 13:43 
Hallo zusammen,

bei der Erweiterung eines Tools welches bei der Verarbeitung Strings byteweise einliest und ausgibt sind Probleme aufgetaucht.
Ich habe in der Vergangenheit standartmäßig Strings im 437er Ascii Codepage eingelesen und verarbeitet.

Nun würde ich auch gerne chinesische Zeichen verarbeiten können. Dazu habe ich die Codepage auf UTF-8 gesetzt.
Das Einlesen der Zeichen funktioniert auch ohne Probleme.

Die Probleme tauchen bei der Ausgabe der Zeichen auf. Ich versuche die Daten in einem festen Satzaufbau auszugeben (jede Zeile hat die gleiche Länge),
allerdings verschieben sich die Zeichen und teilweise wird eine leere Zeile ausgegeben obwohl diese nie eingelesen worden ist.

Deswegen wollte ich mal ganz allgemein fragen ob schon jemand von euch Erfahrungen mit der Verarbeitung von chinesischen Zeichen gemacht hat bzw.
jemand weiß ob man irgendwas beachten muss? Oder ist es vllt doch falsch UTF-8 zu verwenden?

Des weiteren wollte ich noch fragen ob es möglich ist sowohl chinesische Zeichen als
auch lateinische Buchstaben in einer Datei auszugeben. (Beide hätten ja unterschiedliche CodePages falls man sich diese ansehen will)

Vielen Dank!
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 15.07.16 13:57 
Zitat:
Oder ist es vllt doch falsch UTF-8 zu verwenden?


Du mußt das Encoding nehmen die deine Quelle auch benutzt hat. Wenn die utf-8 kodiert war dann ist utf-8 benutzen richtig. Sonst halt nicht.

Zitat:
Des weiteren wollte ich noch fragen ob es möglich ist sowohl chinesische Zeichen als
auch lateinische Buchstaben in einer Datei auszugeben


utf-8 beinhaltet beides.

Zitat:
(Beide hätten ja unterschiedliche CodePages falls man sich diese ansehen will)


Dein Anzeigeprogramm kann kein utf-8 (unter der Annahme utf-8 ist richtig)?

Für diesen Beitrag haben gedankt: haschme
haschme Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 57
Erhaltene Danke: 1



BeitragVerfasst: Fr 15.07.16 14:08 
Danke für die schnelle Antwort!

Also mein Anzeige-Programm kann schon UTF-8 nur sieht die Ausgabe teilweise verschoben aus.

Das Problem ist wahrscheinlich, dass ich nicht genau weiß welches Codepage verwendet wurde.
Von daher habe ich UTF-8 verwendet da es die meisten Zeichen beinhaltet (sofern ich da korrekt informiert bin)

Naja da muss ich wohl oder übel solange Codepages ausprobieren bis ich die richtige gefunden habe oder?^^

Vom allgemeinen Verarbeitungsprozess her können chinesische Zeichen aber genauso wie alle anderen Zeichen auch verarbeitet werden?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 15.07.16 15:34 
Zitat:
Naja da muss ich wohl oder übel solange Codepages ausprobieren bis ich die richtige gefunden habe oder?^^


Am einfachsten ist die Quelle zu fragen wie sie das File kodiert hat. Sonst bleibt nur raten. Entweder selbst oder mit passender Software.

Für diesen Beitrag haben gedankt: haschme
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Fr 15.07.16 18:43 
Zitat:
Das Einlesen der Zeichen funktioniert auch ohne Probleme.

Die Probleme tauchen bei der Ausgabe der Zeichen auf. Ich versuche die Daten in einem festen Satzaufbau auszugeben (jede Zeile hat die gleiche Länge),

Wenn da so stimmt: Es kann durchaus mit der Aufgabe zusammenhängen.

UTF-8 kann ja alle Codepoints darstellen, braucht für manche aber 5 Bytes. Wenn du das in einen normalen C# String einliest, dann wird das nach UCS-2 (oder UTF-16 ?) konvertiert. (Die C# interne Darstellung)

Aber das wichtige: mit dem Indexer myString[2] kommst du NICHT an den zweiten Buchstaben. Du kommst an die zweite Codeunit, 1 bis 2 Codeunits machen einen Codepoint, 1 bis x Codepoints machen einen Buchstaben. Falls du also einfach nach einer bestimmten Anzahl an Codeunits abschneidest, kann es sein, dass du einen Buchstaben zerteilst und das Ergebnis kein gültiger Unicodestring mehr ist!

Für diesen Beitrag haben gedankt: haschme
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4798
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 15.07.16 20:06 
Hallo haschme,

zeig mal deinen (relevanten) Code, wie du die Daten einliest und anzeigst (insbesondere welche Datentypen du dafür verwendest).

Für diesen Beitrag haben gedankt: haschme
haschme Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 57
Erhaltene Danke: 1



BeitragVerfasst: Mo 18.07.16 11:52 
Hier mal ein bischen Code dazu.

Also so lese ich die Zeichen ein
(ich habe mir im nachinein sagen lassen, dass es sich um Japanische Zeichen handelt. Waren wohl doch keine Chinesischen)

Die Eingabedateien haben einen festen Satzaufbau (alle Zeilen sind also gleich lang)

sr ist mein Streamreader.
Als CodePage übergebe ich UTF-8.
Mit ReadBlock lese ich die komplette Zeile ein.
Mit key = GetKey selektiere ich mir einen bestimmten Part herraus.
Diesen füge ich einer Dictionary als Key hinzu.
Als Value dazu speicher ich die jeweilige Zeilennummern in einer List<integer> ab.
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
sr = new StreamReader(filePath, codePage);

char[] buffer = new char[lineLength];

while (!sr.EndOfStream)
{
    rownumber++;

    sr.ReadBlock(buffer, 0, lineLength);

    currentLine = new string(buffer);

    key = GetKey(keyPositions, currentLine);

    if (!myDictionary.ContainsKey(key))
        myDictionary.Add(key,  new List<int>());

    if (myDictionary.ContainsKey(key))
        myDictionary[key].Add(rownumber);
}

Bei der Ausgabe erzeuge ich einen Stream der die Eingabedatei öffnet und mit dem Seek Befehl auf den Anfang der jeweiligen
Zeile in der Eingabedatei zeigt. Danach lese ich diese Zeile in der buffer-Variable vom Typ: byte[] ein.
Diese Zeile schreibe ich dann mit einem Streamwriter in die Ausgabedatei.
ausblenden C#-Quelltext
1:
2:
3:
4:
stream.Seek( ( (long) (lineLength * (myDictionaryCurrentRowNumber - 1) ) ), SeekOrigin.Begin);
stream.Read(buffer, 0, lineLength);

sw.BaseStream.Write(buffer, 0, lineLength);


Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4798
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 18.07.16 12:09 
In welchem Encoding erzeugst du denn die Ausgabedatei (sw)? Und wie läßt du dir denn diese Ausgabedatei anzeigen (in deinem Programm selbst oder per Notepad o.ä) und welche Schriftart verwendest du dabei?

Edit:
Mir ist noch etwas eingefallen: schreibst du explizit die Byte Order Mark (BOM), s. z.B. StreamWriter and UTF-8 Byte Order Marks?

Für diesen Beitrag haben gedankt: haschme
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 18.07.16 12:40 
Wieso interpretierst du du den Inhalt überhaupt als Zeichen? Vom gezeigten Code her ist es irrelevant was da wie kodiert wird. Man könnte einfach Bytes lesen und wegschreiben mit simplen FileStreams ohne StreamReader. Der Sinn des ganzen wäre hilfreich. Versuchst du Zeilen umzusortieren?

Für diesen Beitrag haben gedankt: haschme
haschme Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 57
Erhaltene Danke: 1



BeitragVerfasst: Mo 18.07.16 13:35 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
In welchem Encoding erzeugst du denn die Ausgabedatei (sw)? Und wie läßt du dir denn diese Ausgabedatei anzeigen (in deinem Programm selbst oder per Notepad o.ä) und welche Schriftart verwendest du dabei?

Edit:
Mir ist noch etwas eingefallen: schreibst du explizit die Byte Order Mark (BOM), s. z.B. StreamWriter and UTF-8 Byte Order Marks?


Die Ausgabedatei erzeuge ich in UTF-8. Ich schreibe alles in eine Textdatei (Im gleichen Satzaufbau wie die Eingabedaten) und sehe mir diese mit Notepad++ an.
Wie meinst du die Frage nach der Schriftart? Also im Stream habe ich keine Schriftart explizit angegeben deshalb wird wohl eine Standart schriftart verwendet.
Ich bin mir aber nicht sicher welche es ist.

Zu dem 2. Teil Byte Order Mark (BOM) muss ich mir mal anschauen vielen Dank für die Links!



user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:
Wieso interpretierst du du den Inhalt überhaupt als Zeichen? Vom gezeigten Code her ist es irrelevant was da wie kodiert wird. Man könnte einfach Bytes lesen und wegschreiben mit simplen FileStreams ohne StreamReader. Der Sinn des ganzen wäre hilfreich. Versuchst du Zeilen umzusortieren?


Du hast Recht! Theoretisch könnte ich einfach alles in bytes lassen. Was ich im Prinzip mache ist folgendes, ich selektiere die eingelesenen Strings und speicher diese in der Dictionary als Keys.
Jedesmal wenn ein Key in der Dictionary schon vorhanden ist, wird die betroffene Zeilennummer der Value hinzugefügt.

Das gleiche würde bestimmt auch mit bytes funktionieren, müsste ich mal ausprobieren. Jedoch befürchte ich, dass das Debugen an sich dann etwas unübersichtlicher wird,
da ich den Inhalt der Dictionary nicht mehr so leicht überprüfen kann wenn nur bytes drin stehen. Aber da kann ich mir ja dann vllt Hilfsvariablen nur fürs Debuggen erstellen.

Ich werde es aufjedenfall mal ausprobieren!

PS. Mit Eingabedateien die in Ascii kodiert sind und rein lateinische Buchstaben enthalten funktionierts schon. (Deshalb dachte ich, dass ich nur die CodePage ändern muss und dann klappts auch mit japanischen Zeichen..aber leider ist es wohl doch komplizierter^^)
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Mi 20.07.16 20:06 
user profile iconhaschme hat folgendes geschrieben Zum zitierten Posting springen:
PS. Mit Eingabedateien die in Ascii kodiert sind und rein lateinische Buchstaben enthalten funktionierts schon. (Deshalb dachte ich, dass ich nur die CodePage ändern muss und dann klappts auch mit japanischen Zeichen..aber leider ist es wohl doch komplizierter^^)

Es funktioniert aber nicht weil der Code richtig ist, sondern mehr oder weniger zufällig weil der Text passt ;-)

Zum Beispiel musst du besser zwischen bytes und chars trennen. Hier zum Beispiel:
ausblenden C#-Quelltext
1:
 sr.ReadBlock(buffer, 0, lineLength);					

Die Doku sagt dazu:
Zitat:
Reads a specified maximum number of characters

Deine Zeilen in der Eingabedatei haben also (offenbar) alle die gleiche Anzahl von Buchstaben (nicht Bytes!). Bei englischem Text entspricht ein Buchstabe nur einem Byte.

Aber hier hingegen:
ausblenden C#-Quelltext
1:
stream.Seek( ( (long) (lineLength * (myDictionaryCurrentRowNumber - 1) ) ), SeekOrigin.Begin);					

Musst du einen offset in Bytes übergeben. Wenn nun lineLength = 10 sei und deine erste Zeile hat 12 Bytes, dann bist du damit schon daneben.

Ich an deiner Stelle würde mir einfach ein weiteres Dictionary anlegen, das zu jeder Zeilennnummer die Zeile als string speichert. Offenbar möchtest du ja nur die Zeilen umsortieren.
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 20.07.16 21:52 
- Nachträglich durch die Entwickler-Ecke gelöscht -