Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Array[1..2555] of Char --> Umwandeln in einen String


bs-Hobbit - Do 01.09.05 11:36
Titel: Array[1..2555] of Char --> Umwandeln in einen String
Hallo,

habe folgendes Problem, ich habe ein Array


Delphi-Quelltext
1:
TMeinArray = Array[1..255Of Char                    


Das Steht jetzt z.B. drin:

Art Nr 123 ...

Also ein kleiner Text gefolgt von vielen Leerzeichen ;)

Ich will jetzt NUR den Text in einen String wandeln
also im srting soll dann stehen "Art Nr 123" ohne die Folge leerzeichen, aber mit den "Text Leerzeichen". Wie kriege ich jetzt raus, von wo an nur noch leerzeichen in dem array sind ?

Moderiert von user profile iconTino: Code- durch Delphi-Tags ersetzt.


Martin1966 - Do 01.09.05 11:47

Am besten gehst du Rückwärts vor.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
var
  a: TMeinArray 
  i: integer;
begin
  { ... }

  for i := high(a) downto low(a) do
    if a[i] <> #32 then
      begin
        // I hat jetzt die Position im Array wo sich zum letzten Mal 
        // kein Leerzeichen befindet - also das Ende von dem String. ;-)
 
        break;
      End;
end;


Lg Martin


ManuelGS - Do 01.09.05 11:47

ich glaube der befehl, den du suchst, heißt rtrim (bzw. ltrim).

Gruß, Manuel.


SMO - Do 01.09.05 11:51

Probier's mal so:


Delphi-Quelltext
1:
2:
3:
4:
5:
var
  s: string;
  MeinArray: TMeinArray;

s := TrimRight(MeinArray);


Das schneidet alle Leerzeichen und Kontrollzeichen (alle Chars <= #32) von der rechten Seite des Texts ab. Analog dazu gibt es noch TrimLeft und Trim. Die Funktionen stammen aus der Unit SysUtils, die muss also im uses-Block stehen.


Martin1966 - Do 01.09.05 11:56

Kommen die Funktionen auch mit einem Array klar? Wusste ich noch gar nicht. ;-)


bs-Hobbit - Do 01.09.05 12:02

Mein Delphi meint (Delphi 2005)

Den Befehl TrimRight gibts es nicht :*(

Muss ich eine Unit includen, die hilfe weiss damit auch nicht so recht was anzufangen ^^


Martin1966 - Do 01.09.05 12:03

Wer lesen kann ist klar im Vorteil. :-D

user profile iconSMO hat folgendes geschrieben:
Die Funktionen stammen aus der Unit SysUtils, die muss also im uses-Block stehen.


bs-Hobbit - Do 01.09.05 12:03

Rückwertslauf methode ginge auch, aber TrimRight iterissiert mich jetzt einfach :wink: :roll:

Ich finde es eh zum Kotzen, das ich in einer Typisierten datei keine Strings speicher kann :evil:

Wenn ich mal was zum lesen hätte, delphi hilfe sacht mir dazu nix -.-

Danke für die schnelle hilfe

Thema abgeschlossen :D

Moderiert von user profile iconTino: Vier Beiträge zusammengefasst.


Martin1966 - Do 01.09.05 12:10

user profile iconbs-Hobbit hat folgendes geschrieben:
Wenn ich mal was zum lesen hätte, delphi hilfe sacht mir dazu nix -.-

Ich meine ja auch in diesem Topic. ;-)


bs-Hobbit - Do 01.09.05 12:15

Oh, lol :oops:

aber meinst du ich lese den text soweit^^, ich seh den befehl, kopier ihn, und schau was delphi dazu sagt ;) und delphi war planlos


SMO - Do 01.09.05 12:22

user profile iconMartin1966 hat folgendes geschrieben:
Kommen die Funktionen auch mit einem Array klar? Wusste ich noch gar nicht. ;-)
Der Delphicompiler kann ein Array of Char automatisch in einen temporären String konvertieren, deshalb geht das hier ohne Probleme.

Schön, dass dein Problem gelöst ist, bs-Hobbit. Hier noch ein Tipp: jeder Beitrag von dir hat einen Knopf zum Bearbeiten. Wäre wohl besser, wenn du den benutzt, statt direkt hintereinander mehrere neue Beiträge zu schreiben, die auch noch kaum länger als ein Satz sind. Sowas wird in den meisten Foren nicht gern gesehen. ;)
Ah, und da hat auch schon ein fleißiger Admin die Beiträge zusammengefasst. :)


Martin1966 - Do 01.09.05 12:45

user profile iconbs-Hobbit hat folgendes geschrieben:
aber meinst du ich lese den text soweit^^, ich seh den befehl, kopier ihn, und schau was delphi dazu sagt ;) und delphi war planlos

Dann weißt du ja jetzt, dass es sinnvoll ist die Antworten komplett zu lesen und nicht nicht anschl. einen Frage zu stellen die bereits in einen Antwort an DICH beantwortet wurde. ;-)

Lg Martin


bs-Hobbit - Do 01.09.05 12:52

Ja ok, sorry Leute ich werde mich ändern ;) ich bin ja auch erst seid einigen tagen Online ^^

Noch ne Frage zu den Array Of Char

Ich habe jetzt


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
TMeinRecord = Record
Name:TMeinArray;
Wert:Integer;
end;

TFile = File of TMeinRecord;


Gibt es überhaupt und evt noch eine andere lösung?

es ist ganz schön nervig, das ich keine strings in eine typisierte datei schreiben kann ...

Moderiert von user profile iconTino: Beiräge zusammengefasst.
Moderiert von user profile iconTino: Code- durch Delphi-Tags ersetzt.


Sinspin - Do 01.09.05 13:37

das problem bei der verwendung des typs String mit typisierten dateien ist, das String intern kein echter statischer typ ist sondern eher ein objekt ist.
um dieses problem zu beheben könntest du ShortString verwenden. du solltest dir dann aber im klaren darüber sein das dein string dann nur 255 zeichen lang sein kann.

das ist dann das ergebnis:

Delphi-Quelltext
1:
2:
3:
4:
TMeinRecord = Record
  Name:ShortString;
  Wert:Integer;
end;


SMO - Do 01.09.05 13:48

user profile iconbs-Hobbit hat folgendes geschrieben:
Gibt es überhaupt und evt noch eine andere lösung?

es ist ganz schön nervig, das ich keine strings in eine typisierte datei schreiben kann ...


Nun, statt TMeinArray = Array[1..255Of Char; könntest du auch gleich den alten ShortString Typen benutzen, das ist vielleicht ein bisschen komfortabler, auch wenn es im Endeffekt keinen großen Unterschied macht.

Der Grund, warum der normale String Typ von Delphi nicht für typisierte Dateien verwendet werden kann, ist dass seine Größe variabel ist. Er kann über 2 Milliarden Zeichen aufnehmen, also bis zu 2 GB belegen. Für typisierte Dateien braucht man Datentypen, deren Größe statisch und undveränderlich ist. Bei einem ShortString ist das der Fall, er belegt immer 256 Bytes, selbst wenn nur ein einziger Buchstabe benutzt wird (das erste Byte gibt die Länge an, die restlichen 255 Bytes sind für den Text reserviert).

Mit ShortString sähe dein Record so aus:

Delphi-Quelltext
1:
2:
3:
4:
TMeinRecord = record
  Name: ShortString;  // oder auch Name: string[255]
  Wert: Integer;
end;

ShortString und string[255] sind äquivalent. Wenn "Name" nie länger als 30 Zeichen wird, dann könntest du natürlich auch string[30] benutzen, um Speicherplatz zu sparen. Ein "Name" würde dann 31 Bytes in der Datei belegen: 1 Byte für die tatsächliche Länge, 30 Bytes für den Inhalt.
Dadurch, dass bei diesen kurzen Strings, im Gegensatz zu einem Array of Char, die Länge explizit gespeichert ist, könntest du dir wahrscheinlich sogar das TrimRight sparen.


Motzi - Do 01.09.05 14:04

Kleiner Tipp - nullindizierte Arrays sind zuweisungskompatibel mit PChar! ;)
Wenn du also statt array [1..255of Char das machst array [0..255of Char dann stellt sich das Problem gar nicht!

Generell zum Thema Strings, PChars etc. kann ich mein String-Tutorial empfehlen: http://www.manuel-poeter.de

Gruß, Motzi


bs-Hobbit - Fr 02.09.05 08:41

Danke leute, ich habe jetzt ShortString verwendet, läuft alles soweit


thebe - Fr 02.09.05 09:22

Sollte dein TMeinRecord auch noch mehr als den Namen und den Wert beinhalten, würde ich auf Klassen umsteigen, weil ich die bequemer zu handeln finde als Records. Ich würde eher sagen, anstatt typisierte Dateien zu benutzen, solltest eher Streams verwenden.

Guck Dir mal das folgende Code Beispiel an:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
type
   TMeinRecord = class
      Name: string;
      Wert: integer;

      procedure Serialize(s: TStream);
      procedure Deserialize(s: TStream);
   end;


// Serialize - Werte in einen Stream speichern
procedure TMeinRecord.Serialize(s: TStream);
var
   len: word;   // Benutzte nur ein word für die String Länge, weil ich denke das ein Name niemals über 65k Zeichen kommt
begin
   len := Length(Name);
   s.Write(len, 2);

   s.Write(Name[1], len);
   s.Write(Wert, 4);
end;

// Deserialize - Werte aus einem Stream auslesen
procedure TMeinRecord.Deserialize(s: TStream);
var
   len: word;   // s.o.
begin
   s.Read(len, 2);

   SetLength(Name, len);
   s.Read(Name[1], len);
   s.Read(Wert, 4);
end;


Ich denke mal, wenn Du mal alleine 100 Datensätze in deiner Datei drinne hast und sich diese Namen alle im Bereich zwischen 30 und 40 Zeichen bewegen, sparst dadurch schon min. 21,3 KB. (typisierte Datei: 25,5 KB. Datei basierend auf Streams und dieser Klasse: 3,2 - 4,2 KB)

[EDIT]
Der gesamte Code hier is aussem Kopf geschrieben, für Fehlerfreiheit kann ich nicht garantieren :)


Damit Du auch in den Genuß vom einfachem Zugreifen auf ein Array dieser "Record"-Klassen und dem einfachem Laden/Speichern in eine Datei kommst, hier noch nen bisserl was für Dich.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
type
    TMeinRecordDatei = class
    private
        fArray: array of TMeinRecord;

        procedure SetLength(value: cardinal);
        function GetLength: cardinal;

        procedure SetArray(index: cardinal; value: TMeinRecord);
        function GetArray(index: cardinal): TMeinRecord;

    public
        property Items[index: cardinal]: TMeinRecord read GetArray write SetArray; default;
        Length: cardinal read GetLength write SetLength;

        procedure LoadFromFile(APath: TFileName);
        procedure SaveToFile(APath: TFileName);
    end;

procedure TMeinRecordDatei.SetLength(value: cardinal);
var
    oldlen: cardinal;
    newlen: cardinal;
    i: cardinal;
begin
    oldlen := Length(fArray);
    newlen := value;
    
    SetLength(fArray, value);

    if ( newlen > oldlen ) then
    begin
        for i := oldlen to newlen-1 do
            fArray[i] := TMeinRecord.Create;
    end
    else if ( oldlen > newlen ) then
    begin
        for i := newlen to oldlen-1 do
            fArray[i].Free;
    end;
end;

function TMeinRecordDatei.GetLength: cardinal;
begin
    result := Length(fArray);
end;

procedure TMeinRecordDatei.SetArray(index: cardinal; value: TMeinRecord);
begin
    if ( index >= Length(fArray) ) then
        exit;

    fArray[index] := value;
end;

function TMeinRecordDatei.GetArray(index: cardinal): TMeinRecord;
begin
    result := nil;

    if ( index >= Length(fArray) ) then
        exit;

    result := fArray[index];
end;

procedure TMeinRecordDatei.LoadFromFile(APath: TFileName);
var
    f: TFileStream;
    len: cardinal;
    i: cardinal;
begin
    f := nil;
    Length := 0// Array wird leer gemacht, hier kommt neuer Inhalt    

    try
        try
            if FileExists(APath) then
                f := TFileStream.Create(APath, fmOpenReadWrite or fmShareDenyNone)
            else
                exit;

            f.Read(len, 4);
            Length := len;

            for i := 0 to len-1 do
                fArray[i].Deserialize(f); 
        except
            Length := 0// Fehler beim Laden, das Array wird leer gemacht, wer weiß was alles drinne steht    
        end;
    finally
        if Assigned(f) then
            FreeAndNil(f);
    end;
end;

procedure TMeinRecordDatei.SaveToFile(APath: TFileName);
var
    f: TFileStream;
    len: cardinal;
    i: cardinal;
begin
    f := nil;

    try
        try
            if FileExists(APath) then
                f := TFileStream.Create(APath, fmOpenReadWrite or fmShareDenyNone)
            else
                f := TFileStream.Create(APath, fmCreate or fmShareDenyNone);

            len := Length;
            f.Write(len, 4);

            for i := 0 to len-1 do
                fArray[i].Serialize(f); 
        except
            // Something has to be done here
        end;
    finally
        if Assigned(f) then
            FreeAndNil(f);
    end;
end;


Soo...
und folgendermaßen könntest das Ding dann benutzen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
var
    datei: TMeinRecordDatei;
begin
    datei := TMeinRecordDatei.Create;
    datei.LoadFromFile('C:\somesave.dat');

    datei[3].Name := 'Helga Meier';
    datei[3].Wert := 42;

    datei.SaveToFile('C:\somesave.dat');
    datei.Free;
end;


Komfortabel, oder ?

MfG
- Thebe


Tino - Fr 02.09.05 09:34

Die Verwendung von Streams und so bitte in einem neuen Topic besprechen. Danke. ;-)

Gruß
Tino