Programmeren in REXX/Functies deel 2: verschil tussen versies

Verwijderde inhoud Toegevoegde inhoud
GuyDC (overleg | bijdragen)
Aanvullingen en verbeteringen
GuyDC (overleg | bijdragen)
Toevoegen van Translate functie
Regel 67:
*'''N'''ormal - dit formaat is standaard als geen optie wordt meegegeven. We krijgen de datum in de vorm '''dd mnd jjjj''', bv. 16 mar 2011 (maand in 3 karakters, Engelse namen);
*'''B'''asedate - het aantal dagen sinds 1 januari van het jaar 1. Er wordt hier geen rekening gehouden met de aanpassingen aan de kalender zoals o.a. Paus Gregorius ze doorvoerde in 1582. Voor meer informatie over
tijdrekening, zie [[w:Jaartelling|dit artikel]]. Indien we een restdeling door 7 op een basisdatum uitvoeren, dan bekomen we de dag in de week, waarbij maandag=0 en zondag=6. Anders gezegd, 1 januari 0001 was een dinsdag (want 1//7 = 1).
tijdrekening, zie [[w:Jaartelling|dit artikel]];
*'''D'''ays - het aantal dagen sinds het begin van dit jaar;
*'''E'''uropean - de datum in verkort Europees formaat (dd/mm/jj);
Regel 77:
OORexx biedt ook nog het '''L'''anguage formaat aan, waarbij de datum in lokaal formaat wordt gegeven, bv. 17 januari 2011. Het lokaal formaat wordt in de systeeminstellingen bepaald. Een REXX programma mag geen veronderstellingen maken omtrent het resultaat omdat het programma op een ander systeem in de prak kan lopen als er een andere land-instellingen is gemaakt.
 
Kortom, de meest zinvolle formaten zijn N, B, S, D, M en W. Sorteren kan enkel zinvol gebeuren met het S of B formaat. Het B-formaat is dan weer ideaal om met datums te rekenen zoals we verder zullen leren.
 
Bij devorige eeuwwisseling, enwerd de functie drastisch uitgebreid om de jaar-2000 problematiek te kunnen aanpakken werd deze functie drastisch uitgebreid. De datum kan nu variabel zijn (dus niet enkel die van vandaag). Meer nog, de datum kan via de functie worden omgezet van één formaat in een ander waarbij ook scheidingstekens kunnen gekozen worden. Dit is een voorbeeld:
'''date'''(outputformaat,datum,inputformaat[,outputscheiding][,inputscheiding])
Gisteren = date('Normal',date('B')-1,'B')
De input- en outputformaten zijn zoals we ze hierboven al bestudeerden.
''Gisteren'' zal de waarde «18 Nov 2011» hebben als het vandaag 19 november 2011 zou zijn.
 
Nu zal de ''datum'' die als 2de parameter is meegegeven, en wiens formaat is bepaald door de derde parameter, in het ''outputformaat'' worden teruggegeven. Daarbij kan het scheidingsteken van de input omgezet worden naar het scheidingsteken dat als output gevraagd is. De datum kan in het verleden of de toekomst liggen.
Laten we hierbij een beetje meer uitleg geven:
*de eerste parameter bepaalt nog steeds het formaat waarin we de datum willen terugkrijgen;
*de tweede parameter is de datum die moet worden omgevormd. In dit geval gebruiken we '''date('B')''' om de basisdagen te krijgen en trekken we er één van af om naar gisteren over te gaan;
*de derde parameter maakt aan de functie duidelijk in welk formaat de tweede parameter is opgegeven.
Bovenstaand voorbeeld is het enige waarmee we met datums kunnen rekenen. Daarom is de '''basedate''' zo belangrijk. Dagen bijtellen of aftrekken van andere formaten heeft weinig zin of is zelfs onmogelijk. '''date('N')-1''' zal bijvoorbeeld een ''bad arithmetic operation'' geven, want date('N') is geen getal.
 
Een moeilijke uitleg, daarom snel over naar voorbeelden om het te begrijpen:
Dus, als we een datum ter beschikking hebben in een variabele, dan kunnen we die omvormen. Laten we nog een voorbeeld bekijken:
Gisteren = date('Normal',date('B')-1,'B')
In de veronderstelling dat het vandaag 19 november 2011 is, dan mogen we terecht verwachten dat de functie aan ''Gisteren'' de waarde «18 Nov 2011» zal toekennen. Want zo werkt het:
*de eerste parameter bepaaltzegt nogdat steedswe hetde formaatdatum waarinin wehet de'''N'''ormaal datumformaat willen terugkrijgen;
*de tweede parameter is de datum die moet worden omgevormd. In dit geval gebruiken we '''date('B')''' om de basisdagen te krijgen. enDaar trekkenkunnen we erdan gemakkelijk één van afaftrekken om naar gisteren over te gaan;
*de derde parameter maakt aan de functie duidelijk in welk formaat de tweede parameter is opgegeven, hier dus het B-formaat.
De functie zal dus de uitkomst van de tweede parameter intern omzetten naar het N-formaat.
BovenstaandHet voorbeeld isonderstreept nogmaals het enigebelang waarmeevan wehet metB-formaat datumsals kunnener rekenen. Daarom is de '''basedate'''moet zogerekend belangrijkworden. Dagen bijtellentoevoegen of aftrekken van andere formaten heeftkan niet weinigaltijd zinfoutloos of is zelfs onmogelijk. '''date('N')-1''' zal bijvoorbeeld een ''bad arithmetic operation'' geven, want date('N') is geen getal.
 
Dus,Uiteraard alskan wede eenom datumte tervormen beschikkingdatum hebben inuit een variabele, dan kunnen we diegehaald omvormenworden. Laten we nog een voorbeeld bekijken:
sdate=19530422 /* Dit is een Sorted datum */
say 'Kris is geboren op' date('W',sdate,'S')',' date(,sdate,'S')
Het antwoord dat we hier mogen verwachten is «Kris is geboren op Wednesday, 22 Apr 1953». Mooi is dat nogechter niet. Willen we het volledig in het Nederlands vertalen, dan moeten we wat meer moeite doen, bijvoorbeeld zoals volgt:
sdate=19530422 /* Dit is een Sorted datum */
dagen='maandag dinsdag woensdag donderdag vrijdag zaterdag zondag'
Regel 104 ⟶ 109:
parse var sdate jjjj 5 mm 7 dd /* opsplitsen van sdate */
say 'Kris is geboren op' dag',' dd word(maanden,mm) jjjj
Nu wordt het resultaat «Kris is geboren op vrijdag, 22 april 1953». We kunnen dat nog wat inkorten:
dag=word(dagen,date('B',sdate,'S')//7+1)
say 'Kris is geboren op' dag',' substr(sdate,7) word(maanden,substr(sdate,5,2)) left(sdate,4)
Om te besluiten geven we nog een paaraantal voorbeelden waarbij speciale scheidingstekens worden gebruikt. DieDe tekens kunnen we als 4de en 5devierde parameter geven bij de oproep van de '''date''' functie. De 4de parameter zegtbepaalt welk teken in het resultaat moet verschijnen, en de 5devijfde parameter zegt in de plaats vanbepaalt welk teken diter moetnu komenstaat. AlsStel dat het vandaagnog steeds 19 november 2011 is, dan geven:
IsoDate = date('S',,,'-') «2011-11-19» (toevoegen scheidingsteken)
bdate = date('B',IsoDate,'S',,'-') «734459» (weglaten scheidingsteken)
mindate = date(,,,'-') «19-Nov-2011»(toevoegen scheidingsteken)
In het eerste geval voegen we mintekens toe aan een Sorted datum (jjjjmmdd). REXX weet waar het moet !
<br>In het tweede geval zetten we die IsoDate weer om naar een Basedate, waarbij we deduidelijk functie meegevenmaken dat erde mintekens die in de IsoDate zitten nu moeten verdwijnen (vierde parameter is nullstring).
<br>In het derde geval vragen we mintekens (vierde parameter) toe te voegen in de Normale datum, en weer weet REXX hoe het moet.
<!----------------------------------------------------------------------------------------------->
=TRANSLATE - karakters vertalen=
'''translate'''(string[,outputtabel][,inputtabel][,pad])
Translate is een zeer nuttige functie, maar wel ietwat moeilijk in gebruik, zeker voor beginnelingen. Toch willen we deze moeilijkheid niet uit de weg gaan. Dat we ze hier bespreken zal trouwens ook snel duidelijk worden.
 
In de eenvoudige vorm, waarbij enkel een ''string'' als parameter wordt meegegeven is het nog eenvoudig: de string wordt naar hoofdletters vertaald.
say translate('Zaterdag 17/12 is het feest') &#171;ZATERDAG 17/12 IS HET FEEST&#187;
say translate('Maandag fèteren we met paté') &#171;MAANDAG FèTEREN WE MET PATé&#187;
Uit deze voorbeelden volgt duidelijk dat enkel de normale karakters a tot z naar hoofdletters worden vertaald.
 
Willen we in het laatste voorbeeld ook de geäccentueerde karakters vertalen, dan moeten we dit schrijven:
say translate('Ik had een déjà vu ervaring','AE','àé') &#171;Ik had een dEjA vu ervaring&#187;
Als er een karakter uit de reeks die als derde parameter in de string voorkomt, dan moeten we hem vertalen naar het karakter dat op de overeenkomende plaats in de tweede reeks staat.
Voor elk karakter in de string gaat REXX na of het ook voorkomt in de derde parameter. Zo ja, dan wordt het corresponderende karakter uit de tweede parameter in de plaats gezet. Zoniet blijft het karakter onveranderd.
Dit verklaart waarom nu niet alles naar hoofdletters meer wordt vertaald.
 
De tweede en derde parameter kunnen dus als vertaaltabellen gezien worden. De kortste tabel wordt even lang gemaakt als de langste door er spaties aan toe te voegen.
 
Nog een voorbeeld:
zin="Dit is een volzin"
say translate(zin,'ABCDEFGHI_','abcdefghi ') &#171;DIt_Is_EEn_volzIn&#187;
Nu worden enkel de karakters van a tot i naar hoofdletters vertaald.
 
<p id="XRANGE">Willen we toch het hele alfabet vertalen, dan zouden we het ook volledig moeten uitschrijven. Het kan echter eenvoudiger door middel van de '''xrange''' functie. Deze functie retourneert alle karakters binnen een bereik.</p>
 
Dus nu kunnen we schrijven:
say translate('Ik had een déjà vu ervaring',xrange('A','Z')&#124;&#124;'AE',xrange('a','z')&#124;&#124;'àé')
om toch &#171;IK HAD EEN DEJA VU ERVARING&#187; te bekomen.
 
We zijn echter nog niet uitgepraat over de '''translate''' functie. Ze kan namelijk ook dienen om de karakters van de string op een andere plaats te brengen. Het wordt nu wel nog wat moeilijker om te begrijpen, dus zullen we beginnen met een eenvoudig voorbeeld:
translate('7890','ABCD','9870') &#171;CBAD&#187;
We bewerkstelligen dus het omkeren van de eerste drie karakters.
In tegenstelling tot het "gewone" gebruik van de '''translate''' functie, staat de string die we willen bewerken nu in parameter 2 i.p.v. 1. Maar de functie werkt nog steeds op de manier die we hoger hebben uitgelegd. We nemen het eerste karakter uit de eerste parameter, dus 7. Staat dit in de tabel van parameter 3&nbsp;? Ja, en wel op de derde plaats. Dus, we moeten die 7 vertalen in het derde karakter van de tweede parameter, dus C.
 
We doen hetzelfde voor elk van de karakters, dus 8 wordt B, 9 wordt A en 0 wordt D. Het resultaat is dus CBAD.
 
Dit voorbeeld was goed om het principe uit te leggen, maar van weinig praktisch nut. Laten we nu overgaan tot een meer zinvol gebruik van deze techniek. Daarbij gaan we datums van één formaat in een ander omzetten.
say translate('12345678','16-11-1949','12-34-5678') &#171;16111949&#187;
We hebben dus bereikt dat de mintekens uit de datum zijn verdwenen. Het volgende geeft exact hetzelfde resultaat, maar is véél minder leesbaar geworden:
say translate('abcdefgh','16-11-1949','ab-cd-efgh')
Als we toch met datums bezig zijn, dan wordt de nu volgende schrijfwijze nóg veel intuïtiever:
say translate('DdMmCcJj','16-11-1949','Dd-Mm-EeJj')
Door de karakters in de eerste en derde parameter zorgvuldig te kiezen verhogen we de leesbaarheid en zullen latere voorbeelden veel eenvoudiger te gebruiken zijn. De posities voor de dag stellen we voor d.m.v. "Dd", die voor maand door "Mm" en die voor het jaartal door "EeJj" (E voor eeuw). Niet "dd" want dan treedt er dubbelzinnigheid op zoals we hier kunnen zien:
say translate('ddmmccjj','16-11-1949','dd-mm-ccjj') &#171;11111144&#187;
say translate('ddmmccjj','16-11-1949','Dd-Mm-CcJj') &#171;66119999&#187;
say translate('DdMmCcJj','16-11-1949','dd-mm-ccjj') &#171;D1M1C1J4&#187;
Bij een zuivere permutatie, moeten de tekens van de eerste parameter uniek zijn, anders worden tekens uit tweede parameter meermaals herhaald.
 
In voorgaande voorbeelden haalden we tekens weg. Maar het is ook mogelijk tekens toe te voegen of te veranderen. In volgend voorbeeld maken we een ISO-datum (zie [[w:ISO_8601|ISO 8601]] voor meer informatie):
say translate('CcJj-Mm-Dd','16/11/1949','Dd/Mm/CcJj') &#171;1949-11-16&#187;
Hier is het belangrijk dat de toegevoegde tekens niet in het derde argument voorkomen.
 
Laten we de werking bij permutaties nog eens duidelijk formuleren:
*Parameter 1 bevat het gewenste formaat van het resultaat;
*Parameter 2 bevat de te permuteren gegevens;
*Parameter 3 beschrijft het formaat van de te permuteren gegevens.
Om te eindigen geven we een nog iets langer voorbeeld:
say translate('CcJjMmDd.HhNnSs','16/11/1949 12:14:03','Dd/Mm/CcJj Hh:Nn:Ss') &#171;19491116.121403&#187;
Daar we al "Mm" gebruiken moeten we voor de minuten van het uur spijtig genoeg iets anders kiezen om niet tot dubbelzinnigheid te leiden. Het werd dan maar "Nn".
 
Dit deeltje is zeker niet het gemakkelijkste uit het boek. Het is daarom goed om het nog eens snel te overlopen en na te gaan of alles is begrepen. Deze functie onder de knie krijgen zal dikwijls anders ellenlange logica kunnen vermijden.
 
Hiermee sluiten we het deel over tijdrekening af. We gaan nu verder de functies bestuderen waarmee we getallen kunnen bewerken.
<!----------------------------------------------------------------------------------------------->
=NUMERIC - nauwkeurigheid van bewerkingen bepalen=
Alvorens dieper in te gaan op de numerieke functies moeten we het bevel '''numeric''' nog onder de loep nemen.
Informatie afkomstig van https://nl.wikibooks.org Wikibooks NL.
Wikibooks NL is onderdeel van de wikimediafoundation.