Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   String zerlegen (https://www.delphipraxis.net/69170-string-zerlegen.html)

Luckie 11. Mai 2006 09:11


String zerlegen
 
Ok, das Thema hatten wir schon und die Funktionen pos und copy usw kenne ich. Das ist auch nicht das Problem, also nicht so direkt. Ich habe folgenden String:
Code:
BELEMMER025=11A13061960 GESCEICH026=1 UNTEEICH027=1 LIEFMMER029=061960 KUNDMMER032=00014028 KUNDNUNG033=ELODRIVE GmbH KUNDNUNG034=Stellantriebstechnik          KUNDNUNG035=Potsdamer Strasse 12           PLZKUNDE036=32423 ORTKUNDE037=Minden                        MATCUNDE038=                              BELEATUM039=10.04.2006 AULIEMER042= 61960 @PJL ENTER LANGUAGE = PCL
Und folgenden Record:
Delphi-Quellcode:
  TPJLComments = packed record
    belemmer025: string; // Belegnummer
    aurecmer041: string; // irgendwas Rechnung
    auliemer041: string; // irgendwas Lieferschein
    aulasmer041: string; // irgendwas Lastschrift
    gesceich026: string; // Geschäftsbereich
    unteeich027: string; // Untergeschäftsbereich
    kundmmer032: string; // Kundennummer
    kundnung033: string; // Kundenbezeichnung 1 (Firmenname)
    kundnung035: string; // Kundenbezeichnung 2 (Strasse)
    plzkunde036: string; // PLZ
    ortkunde037: string; // Ort
    matcunde038: string; // MatchCode
    beleatum039: string; // Belegdatum
  end;
Wie bekomme ich jetzt möglichst elegant ohne ohne viel rumzukopieren, die Werte aus dem String in die entsprechenden Felder meines Records? Leider gibt es kein eindeutiges Trennzeichen. Und an dem String kann ich nichts ändern, den bekomme ich so geliefert.

TBx 11. Mai 2006 09:17

Re: String zerlegen
 
Hallo Luckie!

Kommen immer alle Schlüsselworte vor und wenn ja, sind die auch immer in der selben reihenfolge?

Gruß

Thomas

Luckie 11. Mai 2006 09:23

Re: String zerlegen
 
Das kann ich nicht sagen bzw. davon kann ich nicht unbedingt ausgehen. Ich habe hier 12 Beispiele bei denen das wohl der Fall ist. Aber nehmen wir mal den einfachsten Fall, dass es so wäre.

OregonGhost 11. Mai 2006 09:26

Re: String zerlegen
 
Hmm, mit einem relativ einfachen regulären Ausdruck (oder ein wenig Handarbeit) wäre es doch möglich, aus dem String einfach Schlüssel-Wert-Paare zu machen, oder? Wenn es nicht auf maximale Performance ankommt, könnte man RTTI verwenden, um dann die Schlüssel den Feldern im Record zuzuordnen, denn wenn ich das richtig sehe, heißen die Felder genau gleich wie die Schlüssel, nur in Kleinbuchstaben.
Gehe ich recht in der Annahme, dass der Record ebenfalls so vorgegeben ist?

Edit:
Ich sehe gerade, offenbar sind die Felder im String immer gleich lang, weil sie mit Leerzeichen aufgefüllt werden, bzw. die Nummern mit führenden Nullen?

Luckie 11. Mai 2006 09:31

Re: String zerlegen
 
Den Record habe ich mir so zusammengestellt. Könntest du das etwas ausführen? Mit einem kleinen Code-Beispiel eventuell? Mit Regulaärenausdrücken habe ich noch nie gearbeitet.

Also das stimmt, die Bezeichner sind immer gleich lang, aber leider die Werte hinter dem Gleichzeichen nicht.

Jasocul 11. Mai 2006 09:32

Re: String zerlegen
 
Ich würde wie folgt vorgehen:
- Eine Liste der Schlüsselwörter festlegen

- Die zwei Schlüsselwörter feststellen, die die niedrigste Position haben.
- Der Wert zwischen diesen beiden (nach dem "=") gehört zum ersten Schlüsselwort.
- Den String bis zum zweiten Schlüsselwort löschen.
- Und ab hier von vorne, bis alle Schlüsselwörter abgearbeitet sind.

Man kann natürlich noch optimieren, da ab dem zweiten Durchlauf ja das erste Schlüsselwort schon vorliegt.
Ob das eine elegante Lösung ist, musst du selbst entscheiden. Da du bei diesem String aber nicht viel Sicherheit beim Aufbau hast, wirst du ohne Copy, Pos und Delete nicht viel machen können.

OregonGhost 11. Mai 2006 09:44

Re: String zerlegen
 
Also, meine Idee war, einen regulären Ausdruck zu bauen, der alles à la "ABCD012=xxxx " in Schlüssel-Wert-Paare zerlegt. Kann dir im Moment nicht mit Code dienen, höchstens ein recht schnelles Tutorial ans Herz legen. Als Ergebnis hast du dann ein assoziatives Array bzw. Dictionary (ich weiß leider nicht, welche Klasse in Delphi dafür geeignet ist), in dem du also im obigen Beispiel über den Index ABCD012 auf den Wert xxxx zugreifen kannst.

Wenn du über die interne Datenspeicherung frei verfügen kannst, bietet sich eventuell an, es bereits dabei zu belassen, anstatt den "Umweg" über einen Record zu gehen, denn so kannst du ja auch schon über den Namen auf den Wert zugreifen. Wenn du es aber beim Record belassen willst, könntest du jetzt alle Schlüssel-Wert-Paare durchlaufen, jeweils den Index in Kleinbuchstaben umwandeln und dann mithilfe der RTTI im Record das gleichnamige Feld suchen und den Wert hineinschreiben, oder aber eine Funktion schreiben, die das "hardgecodet" übernimmt (also als Parameter Schlüssel und Wert nimmt und dann per case oder so den Wert in das zum Schlüssel gehörende Feld schreibt).

Tut mir leid, kann dir zurzeit nicht mit Code dienen, einerseits zickt mein Delphi rum inklusive der Hilfe, zweitens muss ich bei regulären Ausdrücken jedesmal, wenn ich welche brauch, alles nachlesen :mrgreen: und drittens kenne ich mich mit der Delphi-RTTI überhaupt nicht aus, wobei sie nicht allzu kompliziert zu sein scheint.

Wenn du diesen Weg gehen willst und es an den regulären Ausdrücken hapert, kann ich mich auch noch ein wenig damit beschäftigen, aber das kann dann ein paar Stunden dauern, weil ich meine eigene Entwicklung auch etwas voran bringen muss, Deadline rückt näher ;)

Edit: Ich weiß auch nicht, ob Delphi ohne .NET eine Bibliothek für reguläre Ausdrücke mitbringt, aber da scheint es im Zweifel recht mächtige zum Download zu geben.

marabu 11. Mai 2006 09:48

Re: String zerlegen
 
Zitat:

Zitat von Luckie
Also das stimmt, die Bezeichner sind immer gleich lang, aber leider die Werte hinter dem Gleichzeichen nicht.

Die Daten werden selbstverständlich mit festen Feldlängen übermittelt - und da sie irgendwo auch wieder interpretiert werden, weiß auch jemand die Größenangaben für die einzelnen Felder. Da würde ich mal ansetzen. Vermutlich sind die Daten Bestandteil einer Output-Management-Lösung. Da sollte es ein Anwendungshandbuch geben und auch ein Blick in die HP PJL Technical Reference schadet nicht.

Grüße vom marabu

PS: einfaches Abzählen reicht schon...

OregonGhost 11. Mai 2006 09:51

Re: String zerlegen
 
Hmm, wenn das so ist, kann man sich vieles ersparen, ja, aber das muss nicht so sein. In meinen Augen ist "Leerzeichen-Anzahl Großbuchstaben-Anzahl Zahlen-Gleichheitszeichen" auch genug "Trennzeichen" für die Datensätze. Nachlesen hilft allerdings, falls du irgendwo eine Dokumentation oder einen Quellcode rumliegen hast zu dem Format :)

Luckie 11. Mai 2006 10:03

Re: String zerlegen
 
Zitat:

Zitat von marabu
Die Daten werden selbstverständlich mit festen Feldlängen übermittelt

Das sieht aber nicht so aus. Der Inhalt des Feldes KUNDNUNG033 (Firmanename) ist nicht genauso lang, wie der Inhalt des Feldes KUNDNUNG035 (Strasse).

Zitat:

- und da sie irgendwo auch wieder interpretiert werden, weiß auch jemand die Größenangaben für die einzelnen Felder.
Taj, dieser jemand kann usn aber leider auch nicht helfen.

Zitat:

Da sollte es ein Anwendungshandbuch geben
Siehe oben.

Zitat:

und auch ein Blick in die HP PJL Technical Reference schadet nicht.
Das habe ich hier schon vorliegen, da das aber wohl selbst definierte Variablen sind, hilft das nicht unbedingt.

Zitat:

PS: einfaches Abzählen reicht schon...
Wie meinen? Der Feldinhalt ist doch immer unterschiedlich lang.

OregonGhost 11. Mai 2006 10:07

Re: String zerlegen
 
Ich glaube, marabu meinte, dass die Länge eines bestimmten Feldes in jedem Datensatz gleich lang ist. Also deinem Beispiel entsprechend UNTEEICH027 hat immer Länge 1, LIEFMMER029 hat immer Länge 6 etc. Die Leerzeichen hinter den Feldern (bzw. führenden Nullen) deuten darauf hin. Das wäre mal anhand deiner Beispiel-Datensätze zu überprüfen :)

Luckie 11. Mai 2006 10:10

Re: String zerlegen
 
Das könnte sein. Hm, mal sehen, wa sich daraus bauen kann.

bernau 11. Mai 2006 10:18

Re: String zerlegen
 
Eine Liste der Schlüsselwörter festlegen.

Delphi-Quellcode:
const
  MeineSchluesselwortliste: array [1..5] of string =('BELEMMER025','GESCEICH026','UNTEEICH027','LIEFMMER029','KUNDMMER032');

In dem String mit pos nach den Schlüsselwörtern suchen und vor den schlüsselwörtern in den String ein #13#10 einfügen. Danach in eine TStringlist einlesen.

Delphi-Quellcode:
var
  a:integer;
  x:integer;
....


  for x:=1 to 5 do
    begin
      a:=Pos(MeineSchluesselwortliste[x],DerDatenstring);
      if a>0 then
        insert(#13+#10,DerDatenstring,a);
    end;
   
   MeineStringliste.text:=derDatenstring;
Dann nacheinander mit MeineStringliste.IndexOfName die Werte herauspicken.


(Einfach runtergeschrieben. Nicht getestet.)

Gerd

Luckie 11. Mai 2006 10:21

Re: String zerlegen
 
Das klingt genial. :P Wenns klappt, könnte ich dich küssen. ;)

Klaus01 11. Mai 2006 10:25

Re: String zerlegen
 
vielleicht eine dumme Idee, aber wenn die Felder immer die gleiche Größe haben
könnte man doch auch mit einer record Struktur arbeiten:

Delphi-Quellcode:
TDataSet = record
  case boolean of
    true : s:String;
    false: a:String[10],
            b:string[15],
            c:string[10],
            d:string[1];
end;
Du kannst dann in TDataSet.s den ganzen String einlesen
und mit TDataSet.a das erste Feld auslesen, mußt es nur noch in Feldnamen und Wert trennen.

Nur so eine Idee.

Grüße
Klaus

OregonGhost 11. Mai 2006 10:31

Re: String zerlegen
 
Da die Namen der Felder aber im String vorkommen, geht das nicht so ohne Weiteres, sie müssten vorher entfernt werden :)

Klaus01 11. Mai 2006 10:35

Re: String zerlegen
 
Zitat:

Zitat von OregonGhost
Da die Namen der Felder aber im String vorkommen, geht das nicht so ohne Weiteres, sie müssten vorher entfernt werden :)

..das war mir schon bewußt.

Zitat:

Zitat von Klaus01
das erste Feld auslesen, mußt es nur noch in Feldnamen und Wert trennen.

Grüße
Klaus

Hawkeye219 11. Mai 2006 10:37

Re: String zerlegen
 
@Klaus01

Deine Idee wird aber aus zwei anderen Gründen nicht funktionieren:
1.) dynamische Strings können in varianten Records nicht verwendet werden
2.) ShortStrings besitzen ein Längenbyte, das im Datenrecord nicht enthalten ist.

Gruß Hawkeye

Luckie 11. Mai 2006 10:43

Re: String zerlegen
 
Das könnte auch funktionieren, aber bernaus Methode funktioniert, wie es scheint und sie ist schön einfach und das ist immer ein gutes Zeichen. ;)

TBx 11. Mai 2006 10:51

Re: String zerlegen
 
Hab auch noch ein Codeschnippsel gefunden ...

Delphi-Quellcode:
function DoValueList (ZeiKett:string) : TStringList;
var
  s : String;
  i : integer;
begin
  s := ZeiKett;
  Result := TSTringList.Create;
  while pos ('=', s) > 0 do
  begin
    i := Length (s);
    while (s[i] <> '=') or (s [i-1] = ' ') do dec (i);
    while ((i > 0) and (s [i] <> ' ') ) do dec (i);
    Result.Insert(0, Trim(copy (s, i+1, Length (s))));
    delete (s, i +1, Length (s));
  end;
end;
Es wird ein String in eine ValueList zerlegt, ohne daß man die Names zuvor kennen muß.


Gruß

Thomas

PS:
@Lucki: Bei benraus Lösung solltest Du darauf achten, wirklich alle Schlüsselworte (auch die nicht ausgewerteten) in dem array zu haben, ansonsten könnten einige Values Müll enthalten.

Luckie 11. Mai 2006 10:56

Re: String zerlegen
 
Ich kenne ja die Namen und jeweniger ich mit den Strings hantieren muss, desto besser.

Luckie 14. Mai 2006 13:43

Re: String zerlegen
 
Nun hat sich leider ein problem ergeben: Was wenn in dem String ein Bezeichner vorkommt, den ich nicht kenne und somit nicht im array definieren kann? Ich habe mir jetzt überlegt, dass man da doch irgendwas mit Regulärenausdrücken machen können müsste, da ja alle Bezeichener gleich lang sind, nur Großbuchstabe von A bis Z und die letzten drei zeichen müssen eine Ziffer sein. Icxh wei´ß, dass es da irgendwo eine Delphi Unit gibt, TRegExp oder so. Wäre das damit lösbar? Liefert mir die Unit alles Positionen wo der Ausdruck um String vorkommt?

Luckie 14. Mai 2006 22:28

Re: String zerlegen
 
So, ich habe mir jetzt mal die Unit TRegExpr besorgt. Nur, wie müsste denn der Ausdruck aussehen, der eine Zeichenkette nur aus Großbuchstaben, mit 11 Zeichen Länge findet, wobei die letzten drei Zeichen Ziffern sein müssten? ich habe noch nie was mit Regulärenausdrücken gemacht.

Hawkeye219 14. Mai 2006 22:40

Re: String zerlegen
 
Luckie, was spricht eigentlich gegen die Lösung von onlinekater (Beitrag #20)? Die funktioniert doch zumindest für dein Beispiel bestens, und du benötigst kein Array mit allen Namen.

Gruß Hawkeye

Luckie 14. Mai 2006 22:51

Re: String zerlegen
 
Ups, daran habe ich gar nicht mehr gedacht. :oops: Danke für den Hinweis.

Jetzt weiß ich, warum ich sie nicht benutzt habe: Ich habe die Schleifen nicht verstanden. Könnte mir das noch mal jemand erläutern bitte?

TBx 15. Mai 2006 08:45

Re: String zerlegen
 
Ok, hier kommt der Code nochmal kommentiert:

Delphi-Quellcode:
function DoValueList (ZeiKett:string) : TStringList;
// ****************************************************************************
// Auflösen einer Zeichenkette des Formates "NAME1=WERT1 NAME2=WERT2
//                                           NAME3=WERT3 ......"
// in eine StringList
// ****************************************************************************
// erstellt von Thomas Breitkreuz
// email: [email]tbreitkreuz@breitkreuz-datentechnik.de[/email]
// Codeschnippsel zur Benutzung für Jedermann freigegeben
// ****************************************************************************
var
  s : String;
  i : integer;
begin
  s := ZeiKett;
  Result := TSTringList.Create;
  // ausführen, solange NAME=VALUE - Paare vorhanden sind (diese werden wärend
  // der Bearbeitung laufend aus der Zeichenkette gelöscht
  while pos ('=', s) > 0 do
  begin
    i := Length (s);
    // vom Ende des Strings an solange zurückgehen, bis ein = Zeichen ohne
    // führendes Leerzeichen gefunden wird, es wird davon ausgegangen, daß
    // das = Zeichen dem NAME unmittelbar folgt, dadurch können auch
    // = Zeichen in den Values vorhanden sein, sofern ein Leerzeichen vorgesetzt
    // ist
    while (s[i] <> '=') or (s [i-1] = ' ') do dec (i);
    // nun wird von dem gefundenen = Zeichen aus das nächste Leerzeichen bzw.
    // der Anfang der Zeichenkette gesucht, es wird davon ausgegangen, daß
    // jedem NAME, der nicht am Anfang der Zeichenkette steht, ein Leerzeichen
    // vorausgeht
    while ((i > 0) and (s [i] <> ' ') ) do dec (i);
    // Jetzt wird das gefundene NAME=VALUE-Paar als ersten Eintrag in die
    // Resultliste eingefügt
    Result.Insert(0, Trim(copy (s, i+1, Length (s))));
    // und dann aus der Zeichenkette gelöscht
    delete (s, i +1, Length (s));
    // sollte vor dem ersten NAME=VALUE-Paar noch etwas stehen, so wird dies
    // hier ausgeschnitten und unter dem NAME "$$$TRAILER$$$" in die Resultliste
    // eingefügt
    if (i = 0) and (Length (s) > 0) then
    begin
      Result.Insert(0, '$$$TRAILER$$$=' + Trim (s);
      s := '';
    end;
  end;
end;
Beim Kommentieren ist mir noch eine Unzulänglichkeit aufgefallen: Die Funktion verharrte in einer Endlosschleife, wenn am Anfang der Zeichenkette ein ' =' vor einem "NAME=" vorkam.
Deshalb habe ich noch den Trailer eingeführt.

Ich hoffe, meine Erklärungen sind ausreichend, ansonsten bitte nachfragen.

btw: Hat einer ne Idee, unter welchem Titel man das in die Codelib stellen könnte?

Gruß

Thomas
[Edit] Delphi-Kommentar korrigiert [/Edit]

Luckie 15. Mai 2006 08:57

Re: String zerlegen
 
Besten Dank, jetzt ist alles klar. :thumb:

r2c2 15. Mai 2006 09:18

Re: String zerlegen
 
Das Problem is zwar schon gelöst, aber für all die, dies interessiert, bzw. die, die diesen Thread finden und was Allgemeineres suchen: TDivStrListTDivStrList

In diesem Fall ist aber onlinekaters Version natürlich kürzer und mit weniger Overhead verbunden...

mfg

Christian


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:48 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz