Results 1 to 15 of 15

Thread: Maand naar nummer

  1. #1
    Member Duiker's Avatar
    Join Date
    May 2020
    Location
    Hamont-Achel (Belgie), Pattaya (Thailand)
    Posts
    55

    Maand naar nummer

    De volgende code geeft een foutmelding. Het gaat mis bij Label3.Caption.

    Delphi Code:
    1. procedure TItem321Form.Button1Click(Sender: TObject);
    2. const jan = 1;
    3.       feb = 2;
    4. var Tekst : String;
    5. begin
    6.   Label1.Caption := IntToStr(feb);
    7.   Tekst := 'De maand feb is de tweede maand';
    8.   Label2.Caption := (copy(Tekst, 10, 3));
    9.   Label3.Caption := IntToStr(copy(Tekst, 10, 3));
    10. end;

    Wat doe ik verkeerd, of hoe zou ik het op kunnen lossen?
    De bedoeling is dat ik een 3 letterige maandnaam naar een maandnummer omzet.

  2. #2
    Senior Member Wok's Avatar
    Join Date
    Dec 2002
    Location
    Alkmaar
    Posts
    2,085
    De unit SysUtils heeft 2 functie's om de juiste maand te tonen

    LongMonthNames[nummer:integer] en ShortMonthNames[nummer:integer], deze geven de maand als naam.

    Door handig gebruik te maken van deze array kan je snel het maandnummer terug halen:


    Delphi Code:
    1. Function GetMonthNumber(Const Month:String):Integer; overload;
    2. begin
    3.    Result := IndexText(Month,FormatSettings.LongMonthNames)+1
    4. end;
    10.4.2, Delphi2010, of Lazarus 2.2.0

  3. #3
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747
    weer wat geleerd. Maakte altijd mijn eigen array aan
    Delphi is great. Lazarus is more powerfull

  4. #4
    Member Duiker's Avatar
    Join Date
    May 2020
    Location
    Hamont-Achel (Belgie), Pattaya (Thailand)
    Posts
    55
    In mijn Delphi 7 werkt helaas de genoemde oplossing niet. Het gaat mis bij IndexText.

    Op zicht heb ik het probleem wel opgelost, en kan verder. Maar het knaagt een beetje. De indentifier IndexText kent ie niet.

  5. #5
    Senior Member
    Join Date
    Mar 2002
    Location
    Edam
    Posts
    426
    ..mijn delphi 7 zegt dat hij GetMonthNumber niet kent

    Delphi Code:
    1. function MaandNaarIntstr(maand: string): string;
    2.  Begin
    3.    with tstringlist.create do begin
    4.      commatext:='jan,feb,mrt,apr,mei,jun,jul,aug,sep,okt,nov,dec';
    5.      result:=inttostr(indexof(maand)+1);
    6.      free;
    7.    end;
    8.  End

  6. #6
    Senior Member Wok's Avatar
    Join Date
    Dec 2002
    Location
    Alkmaar
    Posts
    2,085
    IndexText komt pas in hogere versie's voor , ik gok hoger dan xe6 ofzo.

    Willem: GetmonthNumber is een functie die je zelf schrijft. zie code
    Longmontnames bestaat wel.


    Als je een Delphi7 een nieuw project opent, en daar een knop en een label op zet.
    En onderstaande code in plaatst.
    Dan heb je een idee.
    ps: er is geen enkele beveiliging en een foute opgave van je maand geeft een verkeerde waarde.


    Delphi Code:
    1. Unit Unit1;
    2.  
    3. Interface
    4.  
    5. Uses
    6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    7.   Dialogs, StdCtrls;
    8.  
    9. Type
    10.   TForm1 = Class(TForm)
    11.     Label1: TLabel;
    12.     Button1: TButton;
    13.     Procedure Button1Click(Sender: TObject);
    14.   Private
    15.     { Private declarations }
    16.   Public
    17.     { Public declarations }
    18.   End;
    19.  
    20. Var
    21.   Form1             : TForm1;
    22.  
    23. Implementation
    24.  
    25. {$R *.dfm}
    26.  
    27. Function GetMonthNumber(maand: String): String;
    28. Var
    29.   teller            : integer;
    30. Begin
    31.   For teller := low(longmonthnames) To high(longmonthnames) - 1 Do
    32.     If (maand = LongMonthNames[teller]) Then break;
    33.   result := inttostr(teller);
    34. End;
    35.  
    36. Procedure TForm1.Button1Click(Sender: TObject);
    37. Begin
    38.   label1.caption := GetMonthNumber('februari');
    39. End;
    40.  
    41. End.
    Last edited by Wok; 19-Jun-20 at 18:31.
    10.4.2, Delphi2010, of Lazarus 2.2.0

  7. #7
    Member Duiker's Avatar
    Join Date
    May 2020
    Location
    Hamont-Achel (Belgie), Pattaya (Thailand)
    Posts
    55
    Uiteindelijk ga ik onderstaande in mijn programma gebruiken:

    Delphi Code:
    1. function MaandNaarNummer(Maand: String): String;
    2. begin
    3.   with TStringList.Create do
    4.   begin
    5.     CommaText := 'jan,feb,mrt,apr,mei,jun,jul,aug,sep,okt,nov,dec';
    6.     Result := IntToStr(IndexOf(Maand)+1);
    7.     if length(Result) <= 1 then Result := '0' + Result;
    8.     Free;
    9.   end;
    10. end;

    Ik wil een als string zijnde maand van 2 karakters. Dat lijnt mooi uit als het onder elkaar staat.

    Bij deze is iedereen bedankt voor het beantwoorden en meedenken.

  8. #8
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,708
    Misschien een goed moment om het meteen correct aan te leren met try...finally, nu het nog niet ingesleten zit:
    Quote Originally Posted by Duiker View Post
    Delphi Code:
    1. function MaandNaarNummer(Maand: String): String;
    2. begin
    3.   with TStringList.Create do
    4.   try
    5.     CommaText := 'jan,feb,mrt,apr,mei,jun,jul,aug,sep,okt,nov,dec';
    6.     Result := IntToStr(IndexOf(Maand)+1);
    7.     if length(Result) <= 1 then Result := '0' + Result;
    8.   finally
    9.     Free;
    10.   end;
    11. end;
    Ik zou het gebruik van with...do ook nog even af willen raden als je net begint met Delphi; het is shorthand die je je behoorlijk in de staart kan bijten als je niet oplet.
    TMemoryLeak.Create(Nil);

  9. #9
    Net als VideoRipper raad ik het gebruik van "with...do" nog af. En ik wil zelfs een stapje verder gaan en "with...do" voor altijd afraden. Er is niets mis met het concept, maar de leesbaarheid (en overdraagbaarheid) van de code wordt beperkt. Ik heb weleens code onder handen gekregen waar grote blokken code in "with...do" blokken zaten, en dan ook nog "with..do" blokken binnen andere "with...do" blokken (nesting). Het risico dat een andere developer die je code moet onderhouden dan de weg kwijt raakt is groter.

    Terug naar je vraag. Je oplossing met de stringlist heeft ook mijn voorkeur boven de delphi arrays als "LongMonthNames". Die arrays worden voorgevuld met de info zoals het OS opgeeft. Daarmee wordt je code dus meteen afhankelijk van de OS taalinstelling. Op zich is dat wel te omzeilen, maar jouw oplossing is rechtlijniger.

    In aanvulling op VideoRipper zou een verder complete implementatie zoals onderstaand kunnen zijn. Op zich allemaal niet spannend, maar ter info:

    Code:
      function MaandNaarNummer(AMaand: String): String;
      var
        ASl: TStringList;
        AIdx: Integer;
      begin
        ASl := TStringList.Create;
        try
          ASl.CaseSensitive := False;
          ASl.CommaText := 'jan,feb,mrt,apr,mei,jun,jul,aug,sep,okt,nov,dec';
          AIdx := ASl.IndexOf(AMaand);
          if AIdx <> -1 then
            Result := Format('%.*d',[2, AIdx + 1])
          else
            raise Exception.CreateFmt('De maand "%s" is ongeldig', [AMaand])
        finally
          ASl.Free;
        end;
      end;
    Wat heb ik aangepast:
    1. Naamgeving van de parameter (optioneel)
    2. Case insensitive zoeken in de stringlist (dus MaandNaarNummer('DEC') werkt ook)
    3. "with...do" geëlimineerd (optioneel)
    4. Leading zero met Format (optioneel)
    5. Exception raising (optioneel)

    Je zou ook nog met een singleton maand "stringlist" kunnen werken zodat de stringlist niet telkens weer gecreëerd hoeft te worden.
    Last edited by havezet; 20-Jun-20 at 10:06.

  10. #10
    Member Duiker's Avatar
    Join Date
    May 2020
    Location
    Hamont-Achel (Belgie), Pattaya (Thailand)
    Posts
    55
    Nu had ik een mooi duidelijk strak stukje code...
    Neemt niet weg dat ik wel opensta om beter te leren programmeren. Maar er zijn wel wat dingen waar ik mee zit. Ik ben een hobbyist. Natuurlijk zou ik eerst cursussen kunnen volgen. Maar zo vaak programmeer ik nu ook weer niet. Er zullen dus altijd veel vragen blijven. Gelukkig staat er er veel op Internet. Maar het moet ook geen explosie van vragen worden.

    Het niet hoofdletter gevoelig is natuurlijk een sterk punt.

    Dan de volgende vraag: Waarom komt er steeds een "A" voor de variabele? (AMaand)
    Als dat dan toch nodig is, dan zou mijn keuze voor de variabele "AStringList" en "AIndex" zijn. Gewoon voor de leesbaarheid.

    Format('%.*d',[2, AIdx + 1]) Hier krab ik even achter de oren. Maar de volgende site geeft wat uitleg: http://www.delphibasics.co.uk/RTL.asp?Name=format
    Maar om nou te zeggen dat dat meteen duidelijk is.

    De link is nog wel te volgen, tot ik onderstaande tegen kom:
    // One or more of the values may be provided by the
    // data array itself. Note that testing has shown that an *
    // for the width parameter can yield EConvertError.
    ShowMessage(format('In line = <%10.4d>', [1234]));
    ShowMessage(format('Part data driven = <%*.4d>', [10, 1234]));
    ShowMessage(format('Data driven = <%*.*d>', [10, 4, 1234]));

    De representatie is:
    In line = < 1234>
    Part data driven = < 1234>
    Data driven = < 1234>

    Wat is daar niet van begrijp is ".4" Er worden geen nullen toegevoegd, en de lengte is al 4.

    Moet er niet een ; op het einde van de result regel staan?

    Deze regel: raise Exception.CreateFmt('De maand "%s" is ongeldig', [AMaand])
    Die moet ik nog helemaal uitzoeken.

    Je ziet, er lijken zo steeds meer vragen te komen. Terwijl DE vraag nog gesteld moet worden. Maar die stel ik elders op dit forum.

  11. #11
    Dan de volgende vraag: Waarom komt er steeds een "A" voor de variabele? (AMaand)
    Dat is over de jaren heen de conventie in Delphi geworden. De A in het Engels staat voor "een". AIndex lees je als "a index" en betekent dus "een index". Natuurlijk is AMaand een beetje raar door de twee talen, maar de conventie wordt doorgaan taal onafhankelijk toegepast. De "A" is niet verplicht, maar wel gebruikelijk.

  12. #12
    Senior Member Wok's Avatar
    Join Date
    Dec 2002
    Location
    Alkmaar
    Posts
    2,085
    Zo heb je meer letters die gebruikt worden

    een T voor Type en een S voor String

    En antwoord op je andere vragen de ; staat alleen in de code, in het resultaat hoeft het niet te staan
    De ; geeft aan dat er een vervolg regel kom binnen de procedure.
    (Er zijn programmeur zie de ; consequent weg laten op de laatste regel)

    En da het format probleem, probeer te expireren met de waarden, maak van de 10 20, 40 ofzo en kijk wat er gebeurt, dat geld ook voor de 4. kijk wat er gebeurt als je deze groter maakt.
    Oefening baart kunst, de meeste hier leren nog steeds elke dag wat bij. ik geloof dat niemand alles al weet.

    format('In line = <%10.4d>', [1234]);
    Hier vraag je een stringlengte van 10 karakters, waarvan een deel deicmaal opgebouwd is, in dit geval 4 postitie's, maakt de de waarde hoger als de waarde zul je voorloopnullen erbij krijgen.

    ShowMessage(format('Part data driven = <%*.4d>', [10, 1234]));
    die is de waarde vervangen door een *, welke als 'parameter tussen de blokhaken meegegeven word, dus gelijk aan bovenstaande regel

    ShowMessage(format('Data driven = <%*.*d>', [10, 4, 1234]));
    Dit is net als de regel hierboven, alleen staan er nu dirie parameters meegegven, de eerste voor de erste *, de tweede voor de tweede * en de derde parmeter voor de 'd' om als decimaal weer te geven.

    Zoals je al aangaf het staat allemaal in delphi basics, maar met zo'n samengestelde functie is het even puzzelen. Uiteindelijk ga je de voordelen wel zien.


    De try finally end.

    Alles word uitgevoerd wat tussen de try finally staat. Dat kan van alles zijn.
    Maar uiteindelijk kom je bij de finally end dat gedeelde word altijd uitgevoerd.

    En als een onverwacht toch een fout situatie ontstaat, kan je deze opvangen met raise. Execption.
    Een tegenhanger kan zijn Try Except. daar wordt alles gevoerd wat ertussen staat.
    en als het fout gaat komt het deel tussen Except End in beeld

    Ook dit is te vinden in de Delphi Basics.

    Dit soort constructie's voorkomt dat je programma gaat hangen en de dat je het niet meer kan afsluiten, of erger je computer moet herstarten.
    Lees je in en gebruik het waar nodig.

    Je zou ook nog met een singleton maand "stringlist" kunnen werken zodat de stringlist niet telkens weer gecreëerd hoeft te worden.
    Vele wegen leiden tot een oplossing, je kan in dit geval zelfs een constante array gebruiken.
    Maar ook hier geldt, wat wil je bereiken en wat is je doel.
    Het mooie van programmeren dat je vele oplossingen kan maken, de ene een stuk efficiënter dan de ander, en soms spelen er ander belangen mee, ik denk aan vaste afspraken, teamwerk, bedrijfspolicy etc etc


    Succes

    Peter
    Last edited by Wok; 21-Jun-20 at 00:48.
    10.4.2, Delphi2010, of Lazarus 2.2.0

  13. #13
    In Delphi zelf zijn maar een paar prefixes gangbaar.
    • T voor allerhande typen, zoals classes, records en enums. De basistypen, zoals string, integer, float hebben dit niet, maar de daarvan afgeleide simpele typen al wel (TDateTime, TCaption, TComponentName).
    • A voor argumenten (parameters voor procedures en functies) zie je veel terugkomen in de VCL, zeker binnen classes, waar ze vaak dezelfde naam kunnen hebben als een property.
    • I voor interfaces is een standaard die ook buiten Delphi gebruikelijk is.
    • F voor fields is zo gebruikelijk dat de VCL en de IDE er ook op ingericht zijn. Dit zie je aan de code completion van properties (die herkent Get als getter method en F als variabele), maar ook aan de nieuwe JSON serialisatie die bijvoorbeeld niet met properties werkt maar met fields (de gruwel), en daarbij de F negeert bij het automatisch matchen van de variabelenaam met de properties in de JSON.

    Die conventie met A ken ik dan ook alleen voor de parameters, de arguments voor procedures en functies. Door deze te prefixen met A voorkom je naamconflicten met lokale variabelen of properties. Voor diezelfde reden staat er een F voor de (meestal private) fields van een object.

    Gebruikers van Delphi kunnen nog aanvullende (of afwijkende) standaarden hebben.
    De meeste mensen prefixen (lokale) variabelen helemaal niet, maar sommige gebruiken altijd L voor lokale variabelen en/of G voor globals, om dezelfde reden als de A: de scope aanduiden om naamconflicten te voorkomen.

    Anderen gebruiken specifieke letters of reeksen gebruiken om het type aan te duiden. sNaam voor een string. Deze 'Hungarian notation' is voor zover ik weet niet heel gebruikelijk voor algemene variabelen, maar iets vaker wordt het gebruikt voor forms en de controls daarop (edtNaam), al is het ook daar zeker zo logisch om NaamEdit te gebruiken.

    Er zijn er zelfs die een combinatie gebruiken. LiLeeftijd zou dan een lokale integer zijn.

    De prefix A voor alle variabelen, waar havezet mee kwam, is voor mij nieuw. Zo zie je maar, weer wat geleerd.
    1+1=b

  14. #14
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747
    De prefix A voor alle variabelen, waar havezet mee kwam, is voor mij nieuw.
    Mij dus ook. Locale variabelen hebben als naamzijnde geen echte notatie omdat deze na de procedure weer uit het systeem verwijderd worden. als gaat Delphi er slordiger mee om dan Lazarus. Een locale variabele mag daar NIET hetzelfde heten als een functie, property of globale variabele.
    Delphi is great. Lazarus is more powerfull

  15. #15
    Quote Originally Posted by jkuiper View Post
    Mij dus ook.
    Na Jos zijn opmerking dat A voor "argument" zou staan heb ik een korte zoektocht gedaan, want ik was ervan overtuigd dat de A conventie vooral een taalkundige achtergrond had (staat voor "een"). Blijkbaar is de A later in gebruik geraakt als afkorting voor "argument", dit heb ik vaker online gevonden. Maar in de "oude tijd" was dat niet zo. Zelf vind ik het een prima keuze om de A vooral als "argument" afkorting te gebruiken. Mogelijk ga ik mijn eigen conventies aanpassen, ook al zal het na 20+ jaar gebruik lastig uit mijn systeem te halen zijn.

    Toen heb ik voor de lol de unit code van System.Classes in 10.4 bekeken. De A wordt bij variabelen inderdaad bijna niet meer gebruikt. Ik zeg bijna omdat je nog code vindt waar de A ook voor variabelen wordt gebruikt (vast oude code, of code van oudere developers haha).

    Hier is een voorbeeld uit System.Classes:

    Code:
    procedure UnregisterIntegerConsts(AIntegerType: Pointer; AIdentToInt: TIdentToInt;
      AIntToIdent: TIntToIdent);
    var
      I: Integer;
      aLockList: TList<TIntConst>;
      aIntConst: TIntConst;
    begin
    
    <snip>
    
    end;
    Maar in dezelfde unit vind je ook dit:
    Code:
    function TFieldsCache.PopClass(AClass: TClass): TFields;
    var
      LFieldTable: PVmtFieldTable;
      LField: PVmtFieldEntry;
      I: Integer;
    begin
    
    <snip>
    
    end;
    en ietsje verder weer dit:
    Code:
    function ReadComponentDeltaRes(Instance: TComponent; const DeltaCandidates: array of string; const Proc: TGetStreamProc): TComponent;
    var
      HInstance: THandle;
      HRsrc: THandle;
      RootName, Delta, ResName: string;
      S: TStream;
    begin
    
    <snip>
    
    end;
    Zoals je ziet is het een beetje een ratjetoe. Niet moet, alles mag. Dat is het mooie van Pascal, maar van mij hadden ze bij de ontwikkeling van de taal veel stringenter daarin mogen zijn door sommige conventies af te dwingen. Maar dat paste weer niet in de tijdsgeest van "toen".

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •