dbase codepage Problem

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
and4more
Beiträge: 207
Registriert: Do 15. Nov 2012, 19:13
OS, Lazarus, FPC: Windows 10, Manjaro Linux, Lazarus 1.6.4 (32/64 Bit)
CPU-Target: 32 Bit / 64 Bit

dbase codepage Problem

Beitrag von and4more »

Hallo liebes Forum,
ich experimentiere gerade mit Abfragen von dBase-Tabellen. Klappt auch soweit ganz gut, nur hab' ich ein Problem bei Umlauten. Mir ist bekannt, dass dBase im alten DOS-Format speichert (glaube cp850) und Lazarus UTF8 verwendet. Die Tabellen sind lesbar und auch die Abfrage klappt....
...solange eben kein Umlaut abgefragt wird. Habe aktuell folgenden Code:

Code: Alles auswählen

 
    if not ControlsDisabled then DisableControls;
    FilterOptions:=[foCaseInsensitive];
    //Suche nach Buchstaben
    Filter:=Format('NNAME="%s*"',[DBStr]);
    Filtered:=True;
    if ControlsDisabled then EnableControls;
 

Die Variable 'DBStr' enthält den Text aus einer Combobox, der mit ComboBox.Text der Funktion übergeben wird. Das DBGrid aktualisiert bei jeder Änderung der Eingabe, da die Funktion über das OnChange Ereignis gesteuert wird. Interessanterweise wird auch in der Combobox schon der (vorläufig) richtige Name aus der Datenbank gefiltert und angezeigt (Windows) und auch das DBGrid reduziert sich mit der Auswahl auf die noch möglichen Alterativen, außer bei einem Umlaut, dann zeigt nur noch der Combobox.Text den kompletten Namen, während das DBGrid leer dargestellt wird.
Bisherige Versuche mit der Unit 'LConvEncoding', die auch die Umwandlung von UTF8 zu CP850 oder CP437 unterstützt funktionieren leider nicht. Also, entweder nutzt dBase eine andere Codepage oder irgendwas klappt mit der Umwandlung nicht. Ich glaube an Letzteres, denn wenn ich die Datenbankdatei mit einem Texteditor öffne sehe ich eine andere Kodierung/andere Zeichen als im Debugger. Kennt jemand da eine Lösung?
Lazarus 1.6.4 32-Bit + 64-Bit, Windows 10 64-Bit, Manjaro Linux 64-Bit

and4more
Beiträge: 207
Registriert: Do 15. Nov 2012, 19:13
OS, Lazarus, FPC: Windows 10, Manjaro Linux, Lazarus 1.6.4 (32/64 Bit)
CPU-Target: 32 Bit / 64 Bit

Re: dbase codepage Problem

Beitrag von and4more »

...vielleicht noch eine nicht ganz unwichtige Ergänzung: in die Datenbank speichere ich derzeit mit...

Code: Alles auswählen

 
dbf.FieldByName('...').AsString:=EditField.Text;
 

...sollte das möglicherweise besser so sein(?):

Code: Alles auswählen

 
dbf.FieldByName('...').AsString:=UTF8ToCP850(EditField.Text);
 

Also eine Umwandlung in Codepage 850 vor Speicherung in der Datenbank, da ja nach erstem Beispiel, wenn ich es richtig verstanden habe, Lazarus den Text als UTF8 ablegt. Allerdings lesen auch externe Tools, wie z. B. DBFPlus die Datenbank sauber aus, zeigen also keine "verstümmelten" Zeichen.
Lazarus 1.6.4 32-Bit + 64-Bit, Windows 10 64-Bit, Manjaro Linux 64-Bit

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

Re: dbase codepage Problem

Beitrag von wp_xyz »

Eigentlich ist es besser, vor dem Schreiben in die DB UTF8 nach CP850 und gleich nach dem Lesen wieder zurück zu verwandeln. Dann lautet die Regel: Immer wenn man auf die Dbf-Datei zugreift, muss man konvertieren. Leider sind einige Zugriffe versteckt hinter den visuellen Komponenten: DBGrid z.B. liest Strings direkt aus der Datei ohne eigene Konvertierung und versucht die CP850-Strings anzuzeigen, was natürlich schief geht. Du kannst das verhindern, indem du eine Feld-variable für die String-Felder definiertst und deren OnSetText und OnGetText überschreibst (siehe Anhang Projekt dbf_umlaut_cp850).

Wenn du darauf verzichtest, die eigenen String-Funktionen der TDbf-Klasse aufzurufen (ich weiß gar nicht, ob es sowas gibt...), kannst du aber auch die Kodierung unverändert lassen. Dann schreibt ein "cbf.FieldByName('Name').AsString := 'Müller'" halt beim 'ü' zwei Byte (UTF8 = $C3 $BC) statt des einen (CP850 = $81) in die DB. Beim Auslesen bleiben die beiden Bytes unverändert und Lazarus macht daraus wieder ein 'ü'. Nur wenn die DB z.B. den String in Großbuchstaben setzen will, dann werden halt die beiden Bytes evtl. einzeln in Großbuchstaben verwandelt, was den UT8-Codepoint zerstört. Natürlich erkennt ein anderes Programm in so einer dbf-Datei die Umlaute wahrscheinlich nicht.

Beim Suchen und Filtern gibt es das Problem, dass die dbf-Datei Strings zwar als CP850 kodiert ablegt, die Filter-Strings und Suchkriterien aber in der CP1252 erwartet werden. Ich habe das im Source-Code gesehen. In diesem Zusammenhang gibt es auch ein Event OnTranslate, mit dem man das evtl umgehen kann - das habe ich nicht näher untersucht. Wahrscheinlich sind die ganzen String-Neuerungen von FPC3 noch an dieser Unit vorbeigegangen. Wenn du also den Filter-String nach CP1252 konvertierst, geht alles. Siehe Projekt_dbf_umlaut.

Eins ist mir noch aufgefallen: Wenn man einen Index erzeugt hat, funktioniert so manches nicht. Das müsste man sich mal genauer anschauen...

[EDIT]
Ich sehe gerade, dass das Filtern in der Nicht-CP850-Version immer noch nicht geht. Und auch das Locate findet nichts mehr, wenn ich als Suchstring "Mül" eingebe statt dem voreingetragenen "Mü" ?! Also ich würde sagen, an der vollständigen Verwendung der CP850 kommt man nicht vorbei.
Dateianhänge
dbf_umlaut_cp850.zip
(3.32 KiB) 90-mal heruntergeladen
dbf_umlaut.zip
(2.8 KiB) 79-mal heruntergeladen

and4more
Beiträge: 207
Registriert: Do 15. Nov 2012, 19:13
OS, Lazarus, FPC: Windows 10, Manjaro Linux, Lazarus 1.6.4 (32/64 Bit)
CPU-Target: 32 Bit / 64 Bit

Re: dbase codepage Problem

Beitrag von and4more »

@wp_xyz
Also zunächst mal Entschuldigung, dass ich mich erst so verzögert melde, leider war ich beruflich unterwegs und hatte dementsprechend keine Zeit.
Als Erstes muss ich mal ein Riesen-Lob an Dich aussprechen, weil ich es total super finde, dass Du Deine Zeit opferst und keine Mühe scheust den Leuten, in dem Fall mir, weiterzuhelfen.
Ich habe Dein Programm (Umlaut_CP 850) kompiliert. Klappt alles so, wie ich es gerne hätte. Mein Problem ist jetzt, dass ich das in meiner Datenbank momentan so nicht prüfen kann, da ja die Namen schon in UTF8 abgelegt sind. Ich gehe aber davon aus, dass es funktionieren wird. Werde mich mal hinsetzen und alles konvertieren müssen und dann abschließend noch mal berichten.
Lazarus 1.6.4 32-Bit + 64-Bit, Windows 10 64-Bit, Manjaro Linux 64-Bit

and4more
Beiträge: 207
Registriert: Do 15. Nov 2012, 19:13
OS, Lazarus, FPC: Windows 10, Manjaro Linux, Lazarus 1.6.4 (32/64 Bit)
CPU-Target: 32 Bit / 64 Bit

Re: dbase codepage Problem

Beitrag von and4more »

...eine Frage hätte ich aber doch noch: und zwar wenn ich Textstrings vom EditField mit Einträgen in der Datenbank vergleiche, muss es dann

Code: Alles auswählen

 
if (FieldByName('NNAME').AsString=UTF8ToCP850(EdName.Text))...
 

heißen, oder

Code: Alles auswählen

 
if (FieldByName('NNAME').AsString=UTF8ToCP1252(EdName.Text))...
 

?
Lazarus 1.6.4 32-Bit + 64-Bit, Windows 10 64-Bit, Manjaro Linux 64-Bit

and4more
Beiträge: 207
Registriert: Do 15. Nov 2012, 19:13
OS, Lazarus, FPC: Windows 10, Manjaro Linux, Lazarus 1.6.4 (32/64 Bit)
CPU-Target: 32 Bit / 64 Bit

Re: dbase codepage Problem

Beitrag von and4more »

Sooo, hab' das jetzt mal ausprobiert. Allerdings trat nach Konvertierung eines Namens das "Phänomen" auf, dass die ComboBox richtig anzeigt und die Suche funktioniert, aber DBGrid alles abschneidet was nach dem Umlaut kommt, d. h. im DBGrid steht jetzt 'Bl' statt 'Blümlein' oder ein '?' statt des Umlauts. In der Datenbank ist der Name aber noch vollständig und korrekt vorhanden und die UTF8 kodierten Namen werden jetzt alle (natürlich) mit Sonderzeichen, aber komplett, im DBGrid dargestellt.
Lazarus 1.6.4 32-Bit + 64-Bit, Windows 10 64-Bit, Manjaro Linux 64-Bit

and4more
Beiträge: 207
Registriert: Do 15. Nov 2012, 19:13
OS, Lazarus, FPC: Windows 10, Manjaro Linux, Lazarus 1.6.4 (32/64 Bit)
CPU-Target: 32 Bit / 64 Bit

Re: dbase codepage Problem

Beitrag von and4more »

...das mit dem Event OnTranslate hat mir dann auch keine Ruhe gelassen, da ich mich erinnerte so was schon mal irgendwo gelesen zu haben. Das Lazarus-Buch war meine erste Eingebung, da (das alte?) Delphi nix mit UTF8 am Hut hat, und siehe da, für alle die Interesse am Thema haben, da steht, dass sich die Zeichensätze in Abhängigkeit von der dBase-Version unterscheiden. Die DOS-basierten Versionen III und IV benutzen CP437 (!) und ab Version VII sei der Windows-ANSI-Zeichensatz in der BDE (-> Lazarus-Buch?!?) eingestellt. Also gehe ich davon aus, dass dBase Version VII (=meine Einstellung) auch CP1252 verwendet. Weiters steht da noch, dass um DOS codierte Tabellen korrekt anzeigen und bearbeiten zu können nach dem .Open eine Zeichensatzumwandlung durchgeführt werden solle und zwar derart, dass die Eigenschaft 'Transliterate' aller Felder auf 'True' gesetzt werden soll. Vorgeschlagen wird dazu folgender Code

Code: Alles auswählen

 
procedure TMainForm.SetTransliterate;
var
  i:Integer;
begin
  for i:=0 To DBFile.Fields.Count-1 do
    if DBFile.Fields[i] is TStringField then
      TStringField(DBFile.Fields[i]).Transliterate:=True;
end;
 

Dazu soll der OnTranslate Event-Handler folgendermaßen implementiert werden:

Code: Alles auswählen

 
function TMainForm.DBFileTranslate(dbf:TDbf;Src,Dest:PChar;ToOem:Boolean):Integer;
var
  S:String;
  L:Integer;
begin
  S:=StrPas(Src);
  L:=Length(S);
  if L>0 then begin
    S:=ConvertEncoding(S,'CP437',EncodingUTF8);
    if Length(S)>L then SetLength(S,L);
    Move(S[1],Dest^,L+1);
  end;
  Result:=L;
end;
 

Leider geht der Text nicht weiter auf dBase VII oder höher ein, das versickert irgendwo im Äther. Somit ist, mir zumindestens, unklar, ob bei dBase VII oder höher eine entsprechende Konversion erfolgen muss oder ob Lazarus dies automatisch macht und ob, wenn Konversion, die dann nach o. g. Schema (also mit CP1252 statt CP437) ablaufen kann.
Übrigens steht da auch drin, dass eine falsche Interpretation des Zeichensatzes die Datenbanktabelle zerstört (dies für alle, die sich aufregen, dass dBase schlecht sei und bereits eine selbstgeschriebene Anwendung eine Tabelle zerstört habe) :wink:
Lazarus 1.6.4 32-Bit + 64-Bit, Windows 10 64-Bit, Manjaro Linux 64-Bit

and4more
Beiträge: 207
Registriert: Do 15. Nov 2012, 19:13
OS, Lazarus, FPC: Windows 10, Manjaro Linux, Lazarus 1.6.4 (32/64 Bit)
CPU-Target: 32 Bit / 64 Bit

Re: dbase codepage Problem

Beitrag von and4more »

Ich habe jetzt ein bisschen rumexperimentiert, allerdings scheint es mit CP1252 nicht zu klappen. Auch ist mir nicht ganz klar in welchem Zusammenhang die Funktion 'DBFileTranslate' einzusetze ist und wie genau. Vielleicht könnte mir da jemand eine Hilfestellung geben.
Lazarus 1.6.4 32-Bit + 64-Bit, Windows 10 64-Bit, Manjaro Linux 64-Bit

Benutzeravatar
gladio
Beiträge: 217
Registriert: Sa 21. Jun 2014, 06:15
OS, Lazarus, FPC: Win10-64 - aktuelle Lazarus/FPC Standard-Edition
CPU-Target: 64Bit
Wohnort: Rügen

Re: dbase codepage Problem

Beitrag von gladio »

Bei der UTF8-Konvertierung hat sich mit FPC3/Lazarus1.6 einiges geändert, funktioniert nicht mehr alles.
Eventuell findes du hier nützliche Infos:
http://wiki.freepascal.org/Better_Unico ... in_Lazarus

and4more
Beiträge: 207
Registriert: Do 15. Nov 2012, 19:13
OS, Lazarus, FPC: Windows 10, Manjaro Linux, Lazarus 1.6.4 (32/64 Bit)
CPU-Target: 32 Bit / 64 Bit

Re: dbase codepage Problem

Beitrag von and4more »

...hmm, ja da könnte irgendwo eine Lösung drin stecken. Ich hab's mir ein paar Mal durchgelesen, aber leider nicht wirklich verstanden. Wenn ich das richtig interpretiere funktioniert die Konversion zwischen UTF8 und Nicht-UTF8 Codepages automatisch. Allerdings ist mir nicht ganz klar wie Lazarus erkennen soll, dass dBase nicht UTF8-fähig ist und Windows-ANSI benötigt.
Lazarus 1.6.4 32-Bit + 64-Bit, Windows 10 64-Bit, Manjaro Linux 64-Bit

Antworten