[gelöst] UTF8-Kodierte Textdatei / Probleme mit FileHeader

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
TerribleCode
Beiträge: 38
Registriert: Di 18. Nov 2014, 22:50
OS, Lazarus, FPC: Windows 7 [x64]; Lazarus 1.6.4 [i386-win32]; FPC 3.0.2 [win32 i386]
CPU-Target: 64Bit

[gelöst] UTF8-Kodierte Textdatei / Probleme mit FileHeader

Beitrag von TerribleCode »

Tag zusammen!
Ich möchte eine UTF8-Kodierte Textdatei einlesen und verarbeiten...
Das Schema der Datei sieht so aus:

Code: Alles auswählen

1=Gelb
2=Rot
...
Diesen Text möchte ich Zeile für Zeile verarbeiten:

Code: Alles auswählen

procedure TForm1.ButtonReadFileClick(Sender: TObject);
var
  UTF8Text: TextFile;
  Info: TInfoRecord; // selbstdefinierter record
  Line: UTF8String;
begin
  AssignFile(UTF8Text,'C:\Text-UTF8.txt');
  Reset(UTF8Text);
  while not EOF(UTF8Text) do
  begin
    ReadLn(UTF8Text,Line);
    Info.Number:=StrToInt(Copy2SymbDel(Line,'=')); // <-- Hier tritt der Fehler auf
    Info.Description:=Line;
  end;
  CloseFile(UTF8Text);
end;
Ich bekomme mit dem Code oben allerdings ein EConvertError: "1" is an invalid integer
Überspringe ich die erste Zeile, klappt alles so wie es soll. Mit Pos(); bekomme ich erst an vierter Stelle die "1"... Daher gehe ich davon aus das der UTF8-Header das Problem ist. der ist ja bekanntlich drei Zeichen lang.

Hat jemand von euch eine Idee wie ich das Problem in den Griff bekommen kann?
Im Anhang ist ein Beispielprojekt inklusive UTF8-Kodierter Textdatei im ensprechendem Schema...
Dateianhänge
UTF8-Test.zip
MD5=CB5B1D8254D532D968118D36C06B55D5
(2.79 KiB) 60-mal heruntergeladen
Zuletzt geändert von TerribleCode am Di 17. Nov 2015, 15:23, insgesamt 1-mal geändert.

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

Re: UTF8-Kodierte Textdatei / Probleme mit FileHeader

Beitrag von theo »

Dann kopiere doch einfach bei der ersten Zeile den Teil ab dem dritten Char und arbeite in diesem Fall mit dem kopierten String.

shokwave
Beiträge: 475
Registriert: Do 15. Nov 2007, 16:58
OS, Lazarus, FPC: Win11/Ubuntu Budgie (L 3.0 FPC 3.2.2)
CPU-Target: i386, x64
Wohnort: Gera

Re: UTF8-Kodierte Textdatei / Probleme mit FileHeader

Beitrag von shokwave »

Hallo,

ich hab dazu was im englischen Forum gefunden. Das kombiniert mit einer StringList ergibt folgenden Code:

Code: Alles auswählen

unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, strutils;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    ButtonReadFile: TButton;
    CheckBoxSkipFirstLine: TCheckBox;
    Memo: TMemo;
    procedure ButtonReadFileClick(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
  type TInfoRecord = record
    Number: Integer;
    Description: UTF8String;
  end;
 
var
  Form1: TForm1;
  Info: array of TInfoRecord;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.ButtonReadFileClick(Sender: TObject);
var
  TextFilePath: String;
  sl: TStringlist;
  Line: String;
  i: Integer;
  FileStream: TFileStream;
  MarkHolder: Cardinal;
begin
  TextFilePath:=GetCurrentDirUTF8+'\Text-UTF8.txt';
  SetLength(Info,0);
  Memo.Clear;
 
  //Überspringe BOM wenn vorhanden
  FileStream := TFileStream.Create(TextFilePath, fmOpenRead);
  MarkHolder := FileStream.ReadDWord;
  if (MarkHolder and $00FFFFFF) = $00BFBBEF then
    FileStream.Position := 3
  else
    FileStream.Position := 0;
 
  //Stringlist erstellen und aus Stream laden
  sl:=TStringlist.Create;
  sl.LoadFromStream(FileStream);
 
  //Verarbeitung
  for i:= 0 to sl.Count-1 do
  begin
    SetLength(Info,Length(Info)+1);
    Line := sl.Strings[i];
    Memo.Lines.Add(Line);
    TryStrToInt(Copy2SymbDel(Line,'='), Info[Length(Info)-1].Number); //TryStrToInt verhindert eine Exception
    Info[Length(Info)-1].Description:=Line;
    //eingelesene Daten kontollieren
    Memo.Lines.add('Zahl: '+ IntToStr(Info[Length(Info)-1].Number));
    Memo.Lines.add('Beschreibung: '+Info[Length(Info)-1].Description);
  end;
  //Aufräumen
  FileStream.Free;
  sl.free;
end;
 
end.
 
@Theo: Und wenn er dann mal 'ne Datei ohne BOM hat?
mfg Ingo

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

Re: UTF8-Kodierte Textdatei / Probleme mit FileHeader

Beitrag von theo »

shokwave hat geschrieben:@Theo: Und wenn er dann mal 'ne Datei ohne BOM hat?
Dann nimmt er meine UTF8 Tools http://wiki.freepascal.org/UTF8_Tools TCharEncStream
Ich wollte es nur nicht komplizierter machen als nötig, und auch keine "vorgekaute" Lösung liefern.

shokwave
Beiträge: 475
Registriert: Do 15. Nov 2007, 16:58
OS, Lazarus, FPC: Win11/Ubuntu Budgie (L 3.0 FPC 3.2.2)
CPU-Target: i386, x64
Wohnort: Gera

Re: UTF8-Kodierte Textdatei / Probleme mit FileHeader

Beitrag von shokwave »

Du hast ja Recht... :oops:
mfg Ingo

TerribleCode
Beiträge: 38
Registriert: Di 18. Nov 2014, 22:50
OS, Lazarus, FPC: Windows 7 [x64]; Lazarus 1.6.4 [i386-win32]; FPC 3.0.2 [win32 i386]
CPU-Target: 64Bit

Re: UTF8-Kodierte Textdatei / Probleme mit FileHeader

Beitrag von TerribleCode »

Danke für den Tipp mit TryStrToInt. Ist viel Eleganter so :D
Ich bin jetzt allerdings etwas Verwirrt. Es geht um:

Code: Alles auswählen

MarkHolder := FileStream.ReadDWord;
if (MarkHolder and $00FFFFFF) = $00BFBBEF then
Die BOM besteht ja aus drei Bytes, MarkHolder enthält ja aber vier!
Ich verstehe also nicht was genau im if-Statement passiert... Und ich möchte nicht nur das der Code funktioniert, sondern ich wüsste auch gerne was genau da passiert!
Das ist auch der Grund warum ich nicht einfach die UTF8-Tools von theo benutze... Danke trotzdem theo ;)

Für Links zu passender Lektüre oder gar Erläuterungen wäre ich euch sehr dankbar!
LG

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

Re: UTF8-Kodierte Textdatei / Probleme mit FileHeader

Beitrag von theo »

Naja, der geht halt nicht von einem String aus, sondern von einem Stream. Und davon liest er das erste DoubleWord (4 Bytes) und wendet darauf eine Maske an mit AND.
In UTF8Tools ist es vielleicht verständlicher gelöst:

Code: Alles auswählen

 const
  UTF8BOM: string = #$EF#$BB#$BF;
 ..
 if Copy(S, 1, 3) = UTF8BOM then...

TerribleCode
Beiträge: 38
Registriert: Di 18. Nov 2014, 22:50
OS, Lazarus, FPC: Windows 7 [x64]; Lazarus 1.6.4 [i386-win32]; FPC 3.0.2 [win32 i386]
CPU-Target: 64Bit

Re: UTF8-Kodierte Textdatei / Probleme mit FileHeader

Beitrag von TerribleCode »

theo hat geschrieben:[...] Und davon liest er das erste DoubleWord (4 Bytes) und wendet darauf eine Maske an mit AND [...]
Das mit der Maske war wohl das was ich nicht geblickt habe. Googlen hat mir an der Stelle leider auch nicht weiter geholfen...

Naja, jedenfalls habe ich das ganze jetzt so gelöst:

Code: Alles auswählen

procedure TForm1.ButtonReadFileClick(Sender: TObject);
var
  FileStream: TFileStream;
  StringList: TStringList;
  BOMTest: Cardinal=0;
begin
  FileStream:=TFileStream.Create(TextFilePath,fmOpenRead);
  FileStream.ReadBuffer(BOMTest,3);
  if (hexStr(BOMTest,6)='BFBBEF')=False then FileStream.Position:=0; // else überflüssig da ich nun ja eh schon an Position 3 bin..
  StringList:=TStringList.Create;
  StringList.LoadFromStream(FileStream);
  [..]
So klappt´s und ich verstehe es sogar noch :)

Danke für eure Hilfe!

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

Re: UTF8-Kodierte Textdatei / Probleme mit FileHeader

Beitrag von theo »

TerribleCode hat geschrieben:
theo hat geschrieben:[...] Und davon liest er das erste DoubleWord (4 Bytes) und wendet darauf eine Maske an mit AND [...]
Das mit der Maske war wohl das was ich nicht geblickt habe. Googlen hat mir an der Stelle leider auch nicht weiter geholfen...
Google hilft schon: https://de.wikipedia.org/wiki/Bitfeld#Bitmaske

Antworten