![]() |
Parsen von Seitenzahlen
Hallo,
ich habe schon die Suchfunktion sowohl vom Forum als auch von bekannten Suchmaschinen genutzt - leider ohne Ergebnis. Eventuell habe ich auch die falschen Suchbegriffe benutzt. Falls das Thema woanders besser hinpasst, dann bitte ich die Moderatoren, das mal zu verschieben: Ich drucke mit einem Programm viele Bilder. Dabei möchte ich jetzt dem Benutzer die Möglichkeit geben, über ein Edit-Feld die zu druckenden Seiten auszuwählen. Das bieten im Grunde alle Textprogramme, Adobe Reader etc. an. Wenn also z.B: "1-3; 10; 17; 21-23" angegeben wird, dann sollen nur die 8 Seiten 1, 2, 3, 10, 17, 21, 22 und 23 ausgedruckt werden. Wie man Strings zerlegt etc. ist bekannt. Ich habe nur leider Probleme, auf einen Lösungsansatz zu kommen. Ich erwarte keinen fertigen Code. Ich bin für Tipps (auch Suchbegriffe s.o.) dankbar. Schönen Sonntag noch Alex |
Re: Parsen von Seitenzahlen
Deklariere eine 'Liste von Seitenzahlen'
Zerteile die Seitenzahlangabe in Teilstrings, die durch ';' getrennt sind. Jeder Teilstring ist entweder eine Seitenzahl oder ein Bereich. Eine Seitenzahl besteht nur aus Ziffern. Hänge die einzelne Seitenzahl in die Liste. Ein Bereich ist eine Seitenzahl gefolgt von einem '-' gefolgt von einer Seitenzahl. Hänge alle Seitenzahlen zwischen der ersten und der Zweiten in die Liste. Drucke alle in der Liste befindlichen Seiten. |
Re: Parsen von Seitenzahlen
|
Re: Parsen von Seitenzahlen
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo alzaimar und TurboMartin! Danke für Eure Hilfe!
Die Sache mit explode etc. ist mir zu kompliziert, auch wenn sie vermutlich dasselbe macht wie ich. Auch bei der Suche mit dem Suchwort explode habe ich immer nur etwas zum Zerteilen von Strings gefunden. Aber Zitat:
Für Ratschläge und insbesondere Verbesserungen bin ich trotzdem immer noch zu haben. Kann mir bitte noch jemand sagen, ob es (1) eine Möglichkeit gibt, mein Array Of Boolean als offenes Array zu deklarieren und (2) ob mir das speichermäßig Ersparnisse/Vorteile bringt? Gruß, Alex |
DP-Maintenance
Dieses Thema wurde von "mkinzler" von "Programmieren allgemein" nach "VCL / WinForms / Controls" verschoben.
Scheint ein Delphi-Problem zu sein |
Re: Parsen von Seitenzahlen
Zitat:
und dann mit SetLength die Größe ändern Vorteile bringt es dann, wenn es z.B. nur 10 statt 1000 Seiten, da dann ja auch nur 10 Byte im Array nötig sind, + ~12 Byte für die Speicherverwaltung so ist das Array ja 1000 Byte groß (Boolean = 1 Byte) obwohl 1 KB jetzt nicht soooooo groß ist. mehr Speicher könnte man nur noch mit einem SET bzw. einer Bitmaske sparen (1 Bit pro Seite) |
Re: Parsen von Seitenzahlen
Hallo Alex,
Ein Alternativ-Vorschlag: Folgende Routine liefert mir den ersten Teilstring bis zu einem Trenner, oder den ganzen String, wenn es kein Trenner mehr gibt. Gleichzeitig wird der String um den ersten Teilstring verkürzt.
Delphi-Quellcode:
Nun kann ich die Eingabe also Stück für Stück abarbeiten. O.g. Funktion verwende ich in fast jedem Programm irgendwo, sie ist ungeheuer praktisch.
Funtion ExtractString (Var aString : String; Const aDelimiter : String) : String;
Var P : Integer; Begin P := Pos(aDelimiter, aString); If P=0 Then Begin Result := Trim (aString); aString := ''; End Else Begin Result := Trim (Copy (1, p-1)); aString := Trim (Copy (aString, p+Length(aDelimiter), MaxInt)); End End; (* s := '12;345'; t := ExtractString(s,';'); // Liefert t<-'12' und s<-'345' t := ExtractString(s,';'); // Liefert t<-'345' und s<-'' *)
Delphi-Quellcode:
Wie Du siehst, habe ich die Funktion vollständig vom Programm und ihren Strukturen getrennt. Damit ist diese Funktion allgemeingültig und kann in jedem Projekt unmittelbar wiederverwendet werden. Durch die Verlagerung der Problemlösung 'Teilstring extrahieren' ist die Routine auch lesbarer, finde ich.
Type
TBooleanDynArray = Array Of Boolean; ... Procedure CreatePageNumbers (aPageNumberDesc : String; Var aPagesToPrint : TBooleanDynArray); Var pageDesc, rangeStart : String; pagenumber, p, q : Integer; Begin If aPageNumberDesc = '' Then // Initialisieren: Wenn Beschreibung leer ist,... For p := Low(aPagesToPrint) To High (aPagesToPrint) Do // ...dann sollen alle Seiten gedruckt werden aPagesToPrint[p] := True else // Sonst sollen erstmal keine Seite gedruckt werden For p := Low(aPagesToPrint) To High (aPagesToPrint) Do aPagesToPrint[p] := False; While aPageNumberDesc<>'' do Begin // Solange noch etwas in der Seitenangabe drin steht pageDesc := ExtractString (aPageNumberDesc,';'); // Nächsten Teilstring holen If TryStrToInt (pageDesc, pagenumber) Then // Teilstring = einzelne Zahl => Zur Liste hinzufügen aPagesToPrint[pageNumber] := True else Begin rangeStart := ExtractString (pageDesc,'-'); // 1.Teil von <Seite> - <Seite> If TryStrToInt (pageDesc,q) And TryStrToInt (rangeStart,p) Then // Prüfen, ob zwei Nummern vorhanden sind For pageNumber := p to q Do // Ja, also alle Zahlen in die Liste hinzufügen aPagesToPrint[pageNumber] := True Else // Keine gültige Bereichsangabe Raise Exception.Create('Ungültige Angabe'); // Exception und Ende End End End; P.S.: Die Prüfung, ob bei einer Bereichsangabe 'a-b' der Wert a < b ist, habe ich mir erspart, das kannst Du gerne noch implementieren. |
Re: Parsen von Seitenzahlen
Es gibt da noch die Klasse TBits, die IMHO angenehmer und platzsparender ist.
Aber ganz perfekt wäre es so: 1.) string in einzelstücke zerlegen (explode & co) 2.)
Delphi-Quellcode:
ein array of TSeitenEintrag anlegen und befüllen.
TSeitenEintrag = record von,bis:integer end;
3.) dieses Array sortieren (einfaches Selection Sort reicht aus) 4.) Optimieren. Array von hinten nach vorne durchgehen und schauen, ob man anliegende oder überschneidende Seiten von zwei auf einen Eintrag reduzieren kann dieser Schritt ist optional 5.) Suchfunktion schreiben, die array durchläuft und schaut ob es einen Treffer gibt 6.) Punkt 1.) bis 5.) als wiederverwendbare Klassse implementieren Diese Vorgehensweise kann auch folgende Anweisung problemlos umsetzen:
Code:
Das wären die Seiten 1 bis 5 und 60 bis Ende.
1-5;60-
Nachtrag: die Klasse bekommt zusätzlich die Boolean Properties EvenPages und OddPages. Die Suchfunktion von 5.) berücksichtigt diese Flags. Somit können auch "nur gerade Seiten" oder "nur ungerade Seiten" von nur einer Klasse behandelt werden. |
Re: Parsen von Seitenzahlen
Zitat:
Zitat:
Bei mir wäre dies eine Zeile:
Delphi-Quellcode:
Die Erweiterung der Spezifikation um gerade/ungerade Seiten ließe sich durch eine einfache Fallunterscheidung ebenfalls leicht implementieren.
...
else Begin rangeStart := ExtractString (pageDesc,'-'); If pageDesc='' Then pageDesc := IntToStr (TotalPageCount); // <<--- Die Erweiterung ... End; Wie gesagt: Einen Vorteil Deiner Methode sehe ich nicht. Aber das heißt ja nicht, das es ihn nicht gibt. Erstelle doch einfach mal so eine Klasse. Ich befürchte, sie ist ein wenig komplexer als mein 10-Zeiler. Ich befürchte auch, das sie wesentlich langsamer ist. Obwohl das wohl keine große Rolle spielen dürfte. |
AW: Parsen von Seitenzahlen
Da ich derartiges in meinem Projekt benötige, habe ich den Ansatz von alzaimar übernommen. Ich nutze aber eine Integerliste. Zusätzlich habe ich eine Umkehrung mit CreateNumberString hinzugefügt. Hier wird aus einer Integerliste ein String erstellt.
Vielleicht kann es jemand irgendwann mal gebrauchen. Gruss Jens
Delphi-Quellcode:
unit tools.ParseNumbers;
// http://www.delphipraxis.net/934335-post7.html interface uses System.Generics.Collections; function ExtractString(Var aString: string; const aDelimiter: string): string; function CreateNumberList(aNumberDesc: string; aNumberList: TList<Integer>): Boolean; procedure CreateNumberString(var aNumberDesc: string; aNumberList: TList<Integer>); const ValidCharsString = ' ,;-0123456789'; implementation uses System.SysUtils, System.StrUtils; function ExtractString(Var aString: string; const aDelimiter: string): string; Var P: Integer; Begin P := Pos(aDelimiter, aString); If P = 0 Then Begin Result := Trim(aString); aString := ''; End Else Begin Result := Trim(Copy(aString, 1, p - 1)); aString := Trim(Copy(aString, p + Length(aDelimiter), MaxInt)); End End; procedure TrimString(var s: string); begin s := Trim(s); s := ReplaceStr(s, ' -', '-'); s := ReplaceStr(s, '- ', '-'); s := ReplaceStr(s, ',', ';'); s := ReplaceStr(s, ' ;', ';'); s := ReplaceStr(s, '; ', ';'); s := ReplaceStr(s, ' ', ';'); end; function CreateNumberList(aNumberDesc: string; aNumberList: TList<Integer>): Boolean; Var numberDesc, rangeStart: String; number, p, q : Integer; Begin aNumberList.Clear; TrimString(aNumberDesc); While aNumberDesc <> '' do Begin numberDesc := ExtractString(aNumberDesc, ';'); If TryStrToInt(numberDesc, number) Then aNumberList.Add(number) else Begin rangeStart := ExtractString(numberDesc, '-'); If TryStrToInt(numberDesc, q) And TryStrToInt(rangeStart, p) and (p <= q) Then For number := p to q Do aNumberList.Add(number) Else Exit(False); End End; Result := True; End; procedure CreateNumberString(var aNumberDesc: string; aNumberList: TList<Integer>); var i: Integer; begin if aNumberList.Count = 0 then Exit; aNumberDesc := ''; aNumberList.Sort; i := 0; while (i < aNumberList.Count) do begin if (i + 2 < aNumberList.Count) and (aNumberList[i] + 1 = aNumberList[i + 1]) and (aNumberList[i] + 2 = aNumberList[i + 2]) then begin aNumberDesc := aNumberDesc + IntToStr(aNumberList[i]) + '-'; while (i + 1 < aNumberList.Count) and (aNumberList[i] + 1 = aNumberList[i + 1]) do Inc(i); aNumberDesc := aNumberDesc + IntToStr(aNumberList[i]); end else begin aNumberDesc := aNumberDesc + IntToStr(aNumberList[i]); end; Inc(i); if i + 1 < aNumberList.Count then aNumberDesc := aNumberDesc + ';'; end; end; end. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:54 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz