Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Parsen von Seitenzahlen (https://www.delphipraxis.net/137353-parsen-von-seitenzahlen.html)

Schwedenbitter 19. Jul 2009 10:47


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

alzaimar 19. Jul 2009 10:54

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.

TurboMartin 19. Jul 2009 10:57

Re: Parsen von Seitenzahlen
 
Z.B. das hier oder ganz allgemein Hier im Forum suchenexplode/explodeexplode

Schwedenbitter 19. Jul 2009 23:03

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:

Zitat von Schwedenbitter
Wie man Strings zerlegt etc. ist bekannt.

Ich habe es jetzt nach dem Schema von alzaimar gelöst. Den Quellcode habe ich beigefügt, falls nochmal jemand das Bedürfnis hat, bestimmte Seiten zu drucken oder sonstwas damit zu machen. Eine Fehlerbehandlung ist nicht dabei, wird in meinem kompletten Programm über die Abfrage der Eingabe beim Edit-Feld gemacht.
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 20. Jul 2009 05:33

DP-Maintenance
 
Dieses Thema wurde von "mkinzler" von "Programmieren allgemein" nach "VCL / WinForms / Controls" verschoben.
Scheint ein Delphi-Problem zu sein

himitsu 20. Jul 2009 06:57

Re: Parsen von Seitenzahlen
 
Zitat:

Zitat von Schwedenbitter
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?

Seiten: Array of Boolean;

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)

alzaimar 20. Jul 2009 07:23

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:
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<-''
*)
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.
Delphi-Quellcode:
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;
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.

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.

sx2008 20. Jul 2009 08:56

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:
TSeitenEintrag = record von,bis:integer end;
ein array of TSeitenEintrag anlegen und befüllen.
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:
1-5;60-
Das wären die Seiten 1 bis 5 und 60 bis Ende.

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.

alzaimar 20. Jul 2009 18:57

Re: Parsen von Seitenzahlen
 
Zitat:

Zitat von sx2008
Aber ganz perfekt wäre es so:
...

:gruebel: Definiere "perfekt" :shock:

Zitat:

Zitat von sx2008
Diese Vorgehensweise kann auch folgende Anweisung problemlos umsetzen:
Code:
1-5;60-

Das können die anderen -nach entsprechender Modifizierung- auch.
Bei mir wäre dies eine Zeile:
Delphi-Quellcode:
...
    else Begin
      rangeStart := ExtractString (pageDesc,'-');                            
      If pageDesc='' Then pageDesc := IntToStr (TotalPageCount); // <<--- Die Erweiterung
...
End;
Die Erweiterung der Spezifikation um gerade/ungerade Seiten ließe sich durch eine einfache Fallunterscheidung ebenfalls leicht implementieren.

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.

Jens01 17. Aug 2012 15:40

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 00:16 Uhr.
Seite 1 von 3  1 23      

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