UTF8 Zeichenketten durchlaufen?

Für allgemeine Fragen zur Programmierung, welche nicht! direkt mit Lazarus zu tun haben.
Antworten
alfware17
Beiträge: 134
Registriert: Di 14. Dez 2010, 23:27

UTF8 Zeichenketten durchlaufen?

Beitrag von alfware17 »

Hallo bitte nicht lachen (amüsieren ja) über meine scheinbar dumme Frage.
Ich programmiere schon ein bißchen und immer mal wieder mit Lazarus und auch Free-Pascal (mache beruflich aber im IBM-Mainframe Bereich).
Bisher unter MS-DOS und auch unter Windows konnte ich mich darauf verlassen; Strings sind aus einzelnen Zeichen zusammengesetzt, die Ketten kann ich
durchlaufen und manipulieren wie ich will, auf einzelne Werte kann ich mit CHR und ORD zugreifen. Außer bei Tastatur-Abfragen/Sonderkeys und sowas.

Dann kam Linux und damit UTF-8. Ich hatte und habe immer wieder Probleme mit der Konvertierung von Quelltexten und auch Daten, die Umlaute und Sonderzeichen
sind meistens verkehrt. Habe mich schon mit dem Lazarus-UTF8 Projekt beschäftigt, u.a. LVEncoding - okay meine Bildschirmausgaben und die File-Inhalte stimmen
jetzt auch meistens. Der Rückweg Linux->Windows ist meistens genauso steinig, wobei dann noch die Zeilenendenproblematik dazukommen.

Jetzt hatte ich aber ein paar Quelltexte, die sich durch keine automatische UTF-8 Konvertierung beeindrucken lassen. Ich habe 2 Tools benutzt; die Umlaute werden
falsch konvertiert, entweder nur in 1 oder in 3 Bytes aber nicht in 2, so wie ich es auch im Internet recherchiert habe. Die Free-Pascal-IDE zeigt die Windows-Umlaute
richtig an, das Programm läuft dann aber nicht richtig. Korrigiere ich das per Hand, läuft das Programm richtig, nur sieht es in der IDE komisch aus. Wenn ich das nach
Windows zurück bringe und untersuche: voîla alle Umlaute bestehen aus 2 Bytes und sogar die, die im Internet gelistet sind. Also Linux und die IDE haben recht.

Jetzt wollte ich das eben nachbauen, eine kleine Konvertierung, ich habe 11 Zeichen gefunden, die ich in 2 Bytes umsetzen muß. Ging auch. Allerdings habe ich
jetzt ein Problem: Die ganze Zeichenkette kann ich ja lesen und ausgeben. Aber was ist mit den einzelnen Zeichen?! Die können ja plötzlich aus 1 oder 2 oder gar 3 Bytes bestehen.
Die Verbindung "String besteht aus n Charaktern" geht also nicht mehr. Gibt es da etwas Neues oder einen Automatismus? Einen Datentyp der 3 Bytes haben kann?
Eine Routine, die sowas vereinzelt und erkennt (ich habe bisher hart #194 und #195 abgefragt und dann noch ein weiteres Byte gelesen). Das ist aber unschön,
auch weil meine "Zeichen" jetzt kleine Strings geworden sind. Vielleicht bin ich nicht auf dem Stand und da gibts längst eine best pratice dafür, aber wo finde ich sowas?

Danke.
Bernd

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: UTF8 Zeichenketten durchlaufen?

Beitrag von Winni »

Hallo!

Die ganzen String-Funktionen gibt es jetzt mit dem Präfix "utf8"

Zu Deiner Frage:

Code: Alles auswählen

var u : TUTF8char;
     MyString: String;
 
For i := 1 to UTF8Length (MyString) do u := Utf8Copy (MyString,i,1);
 

Es gibt auch UTF8delete, UTF8Pos etc

Winni ( pur 7 Bit ASCII)

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: UTF8 Zeichenketten durchlaufen?

Beitrag von theo »

Alternativ kann man den ganzen String umwandeln mit UTF8Decode, dann sind die Einzelnen Buchstaben WideChars, also 2 Byte (Word) lang.
Diese kann man dann "normal" durchlaufen (1 WideChar = 1 Zeichen). Allerdings auch nur für Unicode bis $FFFF, aber das spielt für "normale" Texte keine Rolle.

https://www.freepascal.org/docs-html/rt ... ecode.html

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: UTF8 Zeichenketten durchlaufen?

Beitrag von Winni »

Hi!

Hier sollte eigentlich ein Axt-Symbol stehen.
Die mag der SQL Server aber nicht:
-------------------------------------------------------------------------------------------------
Allgemeiner Fehler
SQL ERROR [ mysqli ]
Incorrect string value: '\xF0\x9F\xAA\x93[/...' for column 'post_text' at row 1 [1366]
Beim Laden der Seite ist ein SQL-Fehler aufgetreten. Bitte kontaktiere die Board-Administration, falls dieses Problem fortlaufend auftritt.
---------------------------------------------------------------------------------------------------


Das ist wichtig! Und oberhalb $FFFF.

Außerdem Schachfiguren, Dominosteine und Spielkarten!

Aber nix für ungut, Theo - im Prinzip hast Du recht.

Winni

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: UTF8 Zeichenketten durchlaufen?

Beitrag von wp_xyz »

alfware17 hat geschrieben:Jetzt hatte ich aber ein paar Quelltexte, die sich durch keine automatische UTF-8 Konvertierung beeindrucken lassen.

Vielleicht sind sie von Hin- und Herkonvertieren schon beschädigt? Üblicherweise lade ich mir die Quelldatei in Notepad++, da steht rechts unten, welche Kodierung vorhanden ist, und man kann auch im Kodierungsmenü verschiedene Einstellungen ausprobieren. Aber Achtung: das Programm speichert manchmal vorschnell --> unbedingt nur mit einer Kopie arbeiten.

Vielleicht kannst du eine der fraglichen Quelldateien gezippt hier hochladen?

Normalerweise ist es bei Lazarusprogrammen am günstigsten, alles in UTF-8 zu haben. Dann läuft meistens alles richtig. Nur beim Zugriff auf Dateien oder beim Aufruf von Windowsfunktionen kann es Probleme geben.

Wenn du unbedingt alle Zeichen eines Strings durchlaufen musst, gibt es zwei Fälle:

(1) Wenn die zu prüfenden Zeichen im ASCII-Bereich liegen, also < 128, dann kannst du den String wie bisher Byte für Byte durchlaufen, egal ob die anderen Zeichen 2, 3, oder 4 Byte lang sind. Damit kann man z.B. einen String an Leerzeichen und Satzzeichen auftrennen, denn das sind immer nur ASCII-Zeichen. Auch bei einem HTML-String findet man die Tags auf diese Weise. Beispiel so:

Code: Alles auswählen

var
  ch: char;
for i := 1 to Length(HTMLString) do
  if HTMLString[i] = '<' then
     ShowMessage('An Pos ' + IntToStr(i) + ' beginnt ein Tag.');

(2) Ganz selten muss man die einzelnen Zeichen des Strings erkennen, wobei nun auch Nicht-ASCII-Zeichen in Frage kommen sind. Hier sollte noch angemerkt werden, dass der Begriff "Zeichen" bei UTF nicht eindeutig ist. Man kann das 'ä' z.B. als UTF8-Sequenz #$C3#$A4 ansehen, oder aber auch 'a' (#$41) und darüberdruckte Punkte (#$CC#$88) - das erschwert Textsuche extrem. Die folgende Messagebox zeigt zwei gleich aussehende, aber unterschiedlich kodierte 'ä's:

Code: Alles auswählen

ShowMessage(#$C3#$A4 + 'a' + #$CC#$88); 

Um einen UTF8-String "Zeichen" für "Zeichen" zu durchlaufen, nimmt man am einfachsten den for-Iterator aus der Unit LazUnicode:

Code: Alles auswählen

program Project1;
 uses
  LazUnicode;
 var
  s: String;
  ch: String;
  i: Integer;
begin
  s := 'abc-äöü';
  i := 1;
  for ch in s do begin
    WriteLn(ch, ' an Pos. ', i, ', ', Length(ch), ' Byte lang');
    inc(i);
  end;
  ReadLn;
end

Desweiteren gibt es eine Vielzahl von UTF8-relevanten Prozeduren in der Unit LazUtf8. Explizite Konvertierungsfunktionen findest du in der Unit LConvEncoding. Also es gibt wirklich keinen Grund, sich hier etwas selbst zu schreiben.

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: UTF8 Zeichenketten durchlaufen?

Beitrag von Winni »

Hi!

Im Lazarus wiki gibt es eine ausführliche Seite über UTF8 - leider nur auf englisch (oder finnisch oder russisch).

Hier:

https://wiki.lazarus.freepascal.org/UTF8_strings_and_characters

Winni

alfware17
Beiträge: 134
Registriert: Di 14. Dez 2010, 23:27

Re: UTF8 Zeichenketten durchlaufen?

Beitrag von alfware17 »

Hallo zusammen,
ja erstmal vielen Dank für eure schnelle Hilfe. Die UTF8-Bibliotheken finde ich auch alle in diesem Ordner Lazutils wo das LVEncoding drin war, oder?
Muss ich mich mal gründlich damit beschäftigen. Aber das löst zumindestens das Durchlaufen :D

Irgendwie habe ich das Gefühl, mein Windows hat seine eigene Codepage - mal ist es Windows, mal DOS, mal ganz was anderes. Was aber sein könnte, weil ich auch noch viel mit
einer VirtualBox und dort WinXP und Turbo-Pascal hin und her schiebe. Bei einem reinen Java-Projekt und meiner Erinnerung nach vor 2 Jahren mit einem Lazarus Windows/Linux
ging es mit einem Standard-Konverter.

Also ich füge mal ein paar Quelltexte bei.
Im Ordner dict (des Zip-Archivs) das letzte Programm (DictM1 bzw die Unit dazu), wo es unter Linux diese Umlautprobleme sowohl in Kommentaren wie auch Ausgaben gab.
Okay - vorhin bei Anzeige F3 im Totalcommander (zeigt mir auch die Codepage) war das in der Automatikeinstellung auch schon mal was verschieden bei den unterschiedlichen Files.

Im Ordner konvert die jeweils in Windows bzw Linux "lauffähigen" Umlaut_Linux bzw Umlaut_Windows.
Das Umlaut_String ist eine "gemischte Quelle" - ich habe sie mit jeweils den FreePascal IDE in Windows und Linux bearbeitet. Das Spannende daran ist, die Linux IDE zeigt mir die
WIndows-Variante sogar korrekt an, bei der Ausführung schlägt dann aber die Codepage zu, jedenfalls in meinem Terminal, welches auch vermanscht sein kann und nein, ich kann da
nichts einstellen, das Terminal ist echt alt (Linux Mint 17). Wenn ich in der Linux-IDE allerdings die Umlaute tippe auf der Tastatur, sehe ich nichts mehr (WYSIWYG), dann werden sie
aber korrekt compiliert. Die 3.Variante mit dem Linux-Editor(Kate) macht nur Schrott.

Und dann mein eigenes KonvUtf8 Programm, wo das so umgesetzt wird, wie meine jetzige Umgebung ist. Ob es tatsächlich nur die 11 Zeichen sind, die umgesetzt werden
müssen, habe ich noch nicht vollständig geprüft, aber ich kann erstmal den Hauptteil der Arbeit weiter machen.
Im Ordner test das Programm mal in Aktion mit 2 Batches (ich mache die Konvertierung ausschließlich in Windows). Hin- und Rückweg waren okay, das mit den Zeilenenden ist zum Glück
nicht das Problem, das macht das OS schon so wie es das braucht.
Dateianhänge
utfproblem.zip
(459.86 KiB) 165-mal heruntergeladen

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: UTF8 Zeichenketten durchlaufen?

Beitrag von wp_xyz »

Was ist eigentlich dein Ziel? Ein Programm ("test"), das aus DOS und TP-Zeiten stammt, so anzupassen, dass es in DOS (?), Windows und Linux in einem Konsolenfenster die Umlaute und sonstigen Nicht-ASCII-Zeichen der CP1252 richtig anzeigt? Und was genau funktioniert nicht?

alfware17
Beiträge: 134
Registriert: Di 14. Dez 2010, 23:27

Re: UTF8 Zeichenketten durchlaufen?

Beitrag von alfware17 »

wp_xyz hat geschrieben:Was ist eigentlich dein Ziel? Ein Programm ("test"), das aus DOS und TP-Zeiten stammt, so anzupassen, dass es in DOS (?), Windows und Linux in einem Konsolenfenster die Umlaute und sonstigen Nicht-ASCII-Zeichen der CP1252 richtig anzeigt? Und was genau funktioniert nicht?


Ich möchte nur, daß meine Programme, die unter Windows und meist auch unter DOS (mit Einschränkungen halt) laufen, dies auch unter Linux tun und ich ggf, Änderungen im Linux gemacht auch mal wieder zurück transportiert bekomme - ohne daß es zu unschönen Sonderzeichenausgaben kommt. Da war das mit dem Codepage-Salat mein aktuelles Problem. Wie gesagt, vor einiger Zeit hat da ein Standard-UTF8-Konvertierer ausgereicht.

Beim Schreiben des Konvertierungsprogramms fiel mir dann die 1-3 Bytes pro Zeichen Problematik auf und ich stellte mir die Frage, warum muß ich neu erfinden, was bestimmt schon Tausende gemacht haben und wofür es entsprechende Typen und Routinen geben kann.
Nun weiß ich, es gibt - die Antworten haben mir hier sehr geholfen, danke! Und ich habe sogar im Hinterkopf eine Anwendung, wo ich das mal so einbauen werde, weil da ganz viele Zeilen gelesen werden und ich die Analyse mal auf UTF8 umstellen könnte.

Mein Umlaut_String Programm sollte nur mal zeigen, was genau ich meinte mit meinem möglicherweise durch meine Systemlandschaft bedingten Codepage-Salat und was genau und warum mich so naja "fertig" macht.
Wenn die Linux-IDE die Windows-Sonderzeichen anzeigt aber man zur Ausführung doch alles per Hand umstellen mußte und wenn man plötzlich sich auf die UTF8-Konvertierung nicht mehr verlassen kann und die,
denen man einfach nur mal schnell ein neues Programm in Linux zeigen wollte, sagen so geht das aber nicht mit den Umlauten.

Die Konvertierung ist also nur "Mittel zum Zweck" - ich habe halt so 10 Anwendungen, die ich gerne weiter für 16/32/64bit Windows/DOS und ebenso für Linux weiter pflegen möchte - möglichst mit einem Quelltext
und suche da den besten Weg für mich.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: UTF8 Zeichenketten durchlaufen?

Beitrag von wp_xyz »

Ich habe das jetzt mal an einem uralten DOS-Programm von mir durchgespielt. Ziel war, das Programm unter Lazarus kompilieren zu können,und zwar für Windows und Linux.

Zunächst den Quellcode aus dem alten DOS-Archiv in ein Arbeitsverzeichnis unter Windows kopieren. Der erste Teil der Arbeit läuft unter Windows, da sind die meisten Änderungen zu erwarten; und außerdem kenne ich mich da besser aus.

Nachdem das Programm unter Linux arbeiten soll, bei dem die DOS/WIndows-Codeseiten Fremdkörper sind, habe ich mich als erstes entschlossen, konsequent alle Units auf UTF8 umzukodieren. Damit fühlt sich auch Lazarus am wohlsten. ABER: Falls du noch irgendwo ein altes TP/BP in Anwendung hast, dann kannst du die geänderten Dateien dort nicht mehr verwenden.

Das Umkodieren geht sicher auch mit Lazarus, aber ich nehme dafür standardmäßig NotePad++, weil ich damit sicher bin, dass mir die IDE nicht dazwischenfunkt. Also: DOS-Quelltest in Notepad++ laden - rechts unten erscheint als Code-Page information: ANSI. Ist klar - DOS kannte kein UTF8. Da die einzelnen ANSI-Codepages für Notepad++ nicht unterscheidbar sind, wird die Windows-Standardcodepage 1252 genommen. Dadurch werden Umlaute nicht richtig angezeigt, denn die alten DOS-Dateien sind normalerweise als CP850 kodiert. Um Notepad++ unter die Arme zu greifen, gehe ich ins Notepad++ Menü "Kodierung" > "Zeichensatz" > "Westeuropäpisch" > "OEM 850" - nun wird alles als CP850 interpretiert und die Umlaute sind da! Nun muss man das ganze nur noch richtig speichern. Die Datei soll UTF8 werden, daher gehe ich zu Menü "Kodierung" > "Konvertierung zu UTF8 (ohne BOM", oder auch "Konvertierung zu UTF8" - dadurch wird aber ein "Byte-Order-Marker" an den Dateianfang geschrieben, was Probleme geben kann, wenn die Datei später vielleicht in ein altes Delphi geladen wird (D7?).

Wichtig: Falls eine der Datei vorher schon mal in Lazarus geladen war, kann sein, dass selbständig Konvertierungen vorgenommen worden sind. Schlimmstenfalls musst du alles von Hand nachziehen.

Das ganze für alle Units des Projekts wiederholen

Nun kann man die Haupt-Datei in Lazarus öffnen, eine Projektdatei ("Projekt" > "Einfaches Programm") erzeugen und einen ersten Kompilierungsversuch wagen. Bei mir scheiterte das, weil eine allgemein verwendete Unit eine eigene Zeichenumwandlung von "DOS nach OEM" machte, bei der die Sonderzeichen als Char in einer Tabelle eingetragen waren - das geht aber nicht mehr, wenn die Quelltext-Datei UTF8 ist, da ist ein Sonderzeichen ein String. Da ich die Funktion nicht benötige, habe ich sie kurzerhand auskommentiert.

Damit war das Programm lauffähig. Aber: die Konsole zeigt die Sonderzeichen nicht richtig an. Die Konsole läuft auf der Standard-Code-Page 1252, mein Programm schreibt aber UTF8. Zum Glück gibt es eine Prozedur in der Windows-Unit, die Codepage der Konsole auf UTF8 umzustellen: SetConsoleOutputCP(CP_UTF8). Das ganze muss in ein {$IFDEF MSWINDOWS}, damit Linux davon nicht betroffen wird.

Insgesamt also:

Code: Alles auswählen

program xyz;
uses
  {$IFDEF MSWINDOWS}
  Windows,
  {$ENDIF}
  ...  // weitere eigene Units.
 
begin
  {$IFDEF MSWINDOWS}
  SetConsoleOutput(CP_UTF8);
  {$ENDIF}
  ...  // eigener Code
end.

Damit erscheinen die Umlaute in der Konsole richtig.

Das ganze nun unter Linux zum Laufen zu bringen ist nun ein Kinderspiel. Alles funktioniert auf Anhieb.

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1430
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: UTF8 Zeichenketten durchlaufen?

Beitrag von fliegermichl »

@wp_xyz. Dein Beitrag ist meiner Meinung nach durchaus einen Wikieintrag wert.
Ich hatte auch schon des öfteren meinen Kampf mit alten Quellcodes und Umlauten.

Was auch meistens funktioniert, wenn ich die Datei im Lazaruseditor rechte Maustaste -> Dateieinstellungen -> Zeichenkodierung -> UTF8 umgestellt hatte.

Benutzeravatar
six1
Beiträge: 782
Registriert: Do 1. Jul 2010, 19:01

Re: UTF8 Zeichenketten durchlaufen?

Beitrag von six1 »

@fliegermichl:
die erste Anlaufstelle, wenn etwas mit den Zeichensätzen nicht funktioniert, ist bei mir auch, mir mit Notepad++ einen Überblick zu verschaffen.
Da kann man viel Zeit sparen... :idea:
Gruß, Michael

Antworten