/*#! /usr/bin/rexx */ /* - Pour les systemes UNIX ou Gnu/LINUX, verifier et adapter la */ /* premiere ligne ci-dessus ; pour les autres : la retirer */ /* - For Unix and Gnu/Linux, check and adapt the first line above. For */ /* others you can delete it */ /* ****************************************** */ /* DGNUMF - CONVERTISSEUR NOMBRES-MOTS EN LANGUE FRANÇAISE */ /* version 2.0.000 du 2026-08-25 */ /* Copyright 2002 2005 2026 Dominique Guebey */ /* https://www.dg77.net/tekno/manuel/dgnumf.htm */ /* COMMENTAIRES SUPPLEMENTAIRES : voir en fin de listing */ /* MORE COMMENTS : see at the bottom */ /* ******************************************************************** */ /* Ce programme a pour fonction la conversion d'un nombre en */ /* une proposition en francais. Voir exemples plus bas */ /* ****************************************** */ /* CONDITIONS D'UTILISATION */ /* Ce programme est offert sans garantie de fonctionnement. */ /* Ce programme est librement utilisable, modifiable et diffusable, */ /* meme contre paiement, sous la condition que les memes termes seront */ /* applicables a la version ainsi distribuee. */ /* ****************************************** */ /* PARTICULARITES : language REXX, utilisation des fonctions */ /* integrees LENGTH, STRIP, SUBSTR et TRUNC. */ /* La presente version s'applique a des nombres limites de : */ /* - 15 chiffres pour la partie entiere et la partie decimale ; */ /* - Ce nombre peut passer à 14 ou 13 suivant l'utilisation de */ /* virgules ou décimales. */ /* Pour des longeurs superieures, le programme restitue les donnees */ /* fournies en entrée. */ /* ****************************************** */ /* PARAMETRES EN ENTREE */ /* 0- "num" : nombre a traiter. */ /* 1- "fem" : "f" ou "F" si feminin ("une"), facultatif si parametre */ /* suivant non utilise. Sinon tout autre caractere. */ /* 2- "unite" : unite ("EURO", "KILO", "BANANE"), par defaut */ /* le mot "VIRGULE" sera insere s'il y a lieu entre les unites et */ /* decimales. Facultatif si parametre suivant non utilise. */ /* Sinon tout autre caractere. */ /* 3- "casse" : si "min" ou MIN, sortie en caracteres minuscules, */ /* par défaut ce sera en majuscules. Facultatif si parametre */ /* suivant non utilise, sinon tout autre caractere. */ /* 4- "belgosuisse" : "b" ou "B" si belgo-suisse ("septante..."), */ /* (facultatif). */ /* ****************************************** */ /* EXEMPLES */ /* 19.5 -> "DIX NEUF VIRGULE CINQ" */ /* 19.50 x EURO -> "DIX NEUF EUROS CINQUANTE" */ /* 91 f BANANE MIN b -> "nonante et une bananes" */ /* 93 x CHEVAL qsd B -> "NONANTE-TROIS CHEVAUX" */ /* 93 x CHACAL -> "QUATRE-VINGT-TREIZE CHACALS" */ /* -101101 f -> "MOINS CENT UN MILLE CENT UNE" */ /* ****************************************** */ /* INITIALISATIONS */ SIGNAL ON ERROR NAME err SIGNAL ON HALT NAME err SIGNAL ON SYNTAX NAME err phrase = "" sign = "plus" flagm = "" flagu = "" flagt = "" /* Longueur maximale des nombres */ NUMERIC digits 18 /* ENTREE DES PARAMETRES //////////////////////////////////// */ PARSE arg numentre fem unite casse belgosuisse . num = numentre /* test/demo/appel depuis la console */ IF num = '' THEN PARSE UPPER PULL num fem unite belgosuisse . /* AS400 : appel de ce programme avec passage d'arguments */ /* PARSE UPPER ARG num fem unite casse belgosuisse . */ /* ////////////////////////////////////////////////////////// */ /* ------------------------------------- */ /* Verifier si zone est numerique */ IF datatype(num, N) \= 1 THEN RETURN num /* ------------------------------------- */ /* gerer le signe */ SELECT WHEN num < 0 THEN DO phrase = "MOINS" signe = "-" m = num * -1 ; num = m END OTHERWISE phrase = "" END /* ------------------------------------- */ /* conserver les decimales */ dec = 0 calc = TRUNC(num, 0) xdec = num - calc /* entiers = num - dec */ PARSE VAR num entiers '.' dec /* Ôte les zéros de gauche */ entiers = STRIP(entiers, L, '0') IF entiers == '' THEN DO zon = phrase "ZERO" ; phrase = zon END /* ------------------------------------- */ call traite /* PLURIEL ***************************** */ IF num >= 2 THEN plur = "X" /* ------------------------------------- */ /* Mettre l'unite s'il y a lieu (4e argument) */ IF unite \== "" & unite \== 'unite' & plur == "X" THEN DO /* ne rien faire pour mot termine par "s" ou "x" */ lz = LENGTH(unite) /* mot > 1 car et fini par "al" */ IF lz > 1 & SUBSTR(unite,(lz-1),2) == "AL" THEN DO IF unite \== 'AVAL' & unite \== 'BAL' & unite \== 'CARACAL' & , unite \== 'CARNAVAL' & unite \== 'CEREMONIAL' & unite \== 'CHACAL' & , unite \== 'CHORAL' & unite \== 'COPAL' & unite \== 'FESTIVAL' & , unite \== 'FINAL' & unite \== 'GAVIAL' & unite \== 'MISTRAL' & , unite \== 'NARVAL' & unite \== 'NAVAL' & unite \== 'NOPAL' & , unite \== 'PAL' & unite \== 'RECITAL' & unite \== 'REGAL' & , unite \== 'RORQUAL' & unite \== 'SERVAL' & unite \== 'SISAL' THEN DO ztrav = SUBSTR(unite,1,(lz-1)) || 'UX' ; unite = ztrav END ELSE DO /* on met simplement "s" a la fin */ zon = unite || 'S' ; unite = zon END END /* mot > 2 car et fini par "ail" */ IF lz > 2 & SUBSTR(unite,(lz-2),3) == "AIL" THEN DO IF unite \== 'ATTIRAIL' & unite \== 'BERCAIL' & unite \== 'CAMAIL' & , unite \== 'CHANDAIL' & unite \== 'DETAIL' & unite \== 'EPOUVANTAIL' & , unite \== 'EVENTAIL' & unite \== 'GOUVERNAIL' & unite \== 'MAIL' & , unite \== 'PORTAIL' & unite \== 'RAIL' & unite \== 'SERAIL' THEN DO ztrav = SUBSTR(unite,1,(lz-2)) || 'UX' ; unite = ztrav END ELSE DO /* on met simplement "s" a la fin */ zon = unite || 'S' ; unite = zon END END /* mot > 2 car et fini par "ou" */ IF lz > 2 & SUBSTR(unite,(lz-1),2) == "OU" THEN DO IF unite \== 'BIJOU' & unite \== 'CAILLOU' & unite \== 'CHOU' & , unite \== 'GENOU' & unite \== 'HIBOU' & unite \== 'JOUJOU' & , & unite \== 'POU' THEN DO zon = unite || 'S' ; unite = zon END ELSE DO /* "x" a la fin */ zon = unite || 'X' ; unite = zon END END /* cas general */ lz = LENGTH(unite) IF SUBSTR(unite,lz,1) \== 's' & SUBSTR(unite,lz,1) \== 'S' , & SUBSTR(unite,lz,1) \== 'x' & SUBSTR(unite,lz,1) \== 'X' THEN DO zon = unite || 'S' ; unite = zon END END zon = phrase unite ; phrase = zon /* ------------------------------------- */ /* traiter les decimales ex: xdec=0.1 dec=1 */ IF dec > 0 THEN DO IF unite == "" THEN DO unite = "VIRGULE" zon = phrase unite ; phrase = zon END /* "ZERO..." initiaux */ mult = 1 DO UNTIL ndec = 0 mult = mult * 10 calc = xdec * mult edec = TRUNC(calc, 0) IF edec == 0 THEN DO zon = phrase "ZERO" ; phrase = zon END ndec = calc - edec END /* num = calc */ num = dec /* ------------------------------------- */ call traite END /* ------------------------------------- */ /* SORTIE : cf aussi fin "err" */ sortie: /* AS400 */ /* 'CHGDTAARA DTAARA(*LDA (201 328)) VALUE('''phrase''')' */ /* EXIT */ /* Standard : */ /* Conversion en majuscules ou minuscules */ IF casse == 'MIN' | casse == 'min' THEN PARSE LOWER VALUE phrase WITH phrasex ELSE PARSE UPPER VALUE phrase WITH phrasex phrase = phrasex SAY phrase /* PULL */ RETURN phrase /* ************************************** TRAITE : separe le nombre en groupes de 3 chiffres, appelle TRANSF pour chacun A noter : limitation a 999 999 999 999 ci-dessous, longueur admise : 20 chiffres (cf initialisations) ************************************** */ traite: IF num > 999999999999999 THEN DO /* renvoie entree avec parties entiere et decimale */ phrase = numentre SAY phrase EXIT END /* ------------------------------------- */ /* traiter les centaines de milliards */ IF num > 999999999999 THEN DO n = TRUNC(num % 1000000000000, 0) num = num // 1000000000000 IF n > 0 THEN DO CALL TRANSF phrase = phrase "MILLE" END IF num < 1000000000 THEN phrase = phrase "MILLIARDS" END /* ------------------------------------- */ /* traiter les milliards */ IF num > 999999999 THEN DO n = TRUNC(num % 1000000000, 0) num = num // 1000000000 CALL TRANSF IF n == 1 THEN mot = "MILLIARD" ELSE mot = "MILLIARDS" zon = phrase mot ; phrase = zon END /* ------------------------------------- */ /* traiter les millions */ IF num > 999999 THEN DO n = TRUNC(num % 1000000, 0) num = num // 1000000 IF n > 0 THEN DO CALL TRANSF IF n == 1 THEN mot = "MILLION" ELSE mot = "MILLIONS" zon = phrase mot ; phrase = zon END END /* ------------------------------------- */ /* traiter les milliers */ IF num > 999 THEN DO n = TRUNC(num % 1000, 0) num = num // 1000 IF n > 0 THEN DO flagm = "X" CALL TRANSF mot = "MILLE" zon = phrase mot ; phrase = zon END END /* ------------------------------------- */ /* traiter les unites */ IF num > 0 THEN DO n = num // 1000 flagu = "X" CALL TRANSF END RETURN /* ************************************** */ /* TRANSF : separe centaines (c) dizaines (d) unites(u) */ /* d'un nombre de trois chiffres, puis effectue la */ /* conversion en mots */ transf: c = n % 100 cent = c * 100 diz = TRUNC(n, 0) - cent d = diz % 10 u = diz - (d * 10) /* CENTAINES */ mot = " " SELECT WHEN c == 2 THEN mot = "DEUX" WHEN c == 3 THEN mot = "TROIS" WHEN c == 4 THEN mot = "QUATRE" WHEN c == 5 THEN mot = "CINQ" WHEN c == 6 THEN mot = "SIX" WHEN c == 7 THEN mot = "SEPT" WHEN c == 8 THEN mot = "HUIT" WHEN c == 9 THEN mot = "NEUF" OTHERWISE END IF mot \== " " THEN DO zon = phrase mot ; phrase = zon END mot = " " IF c = 1 THEN mot = "CENT" IF c > 1 THEN DO testot = d + u IF testot = 0 THEN mot = "CENTS" ELSE mot = "CENT" END IF mot \== " " THEN DO zon = phrase mot ; phrase = zon END /* DIZAINES */ mot = " " SELECT WHEN d == 1 THEN IF u == 0 THEN mot = "DIX" WHEN d == 2 THEN mot = "VINGT" WHEN d == 3 THEN mot = "TRENTE" WHEN d == 4 THEN mot = "QUARANTE" WHEN d == 5 THEN mot = "CINQUANTE" WHEN d == 6 THEN mot = "SOIXANTE" WHEN d == 7 THEN IF belgosuisse == "b" | belgosuisse == "B" THEN mot = "SEPTANTE" ELSE mot = "SOIXANTE" WHEN d == 8 THEN DO IF u == 0 THEN mot = "QUATRE-VINGTS" ELSE mot = "QUATRE-VINGT" flagt = 'z' END WHEN d == 9 THEN DO IF belgosuisse == "b" | belgosuisse == "B" THEN mot = "NONANTE" ELSE mot = "QUATRE-VINGT" flagt = 't' END OTHERWISE END IF mot \== " " THEN DO zon = phrase mot ; phrase = zon END /* UNITES */ mot = " " SELECT WHEN u == 0 THEN SELECT /* WHEN d == 1 THEN mot = "DIX" */ WHEN d == 7 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "DIX" WHEN d == 9 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "DIX" OTHERWISE END WHEN u == 1 THEN DO zun = "UN" IF flagu = "X" & fem == "f" | flagu = "X" & fem == "F" THEN zun = "UNE" SELECT WHEN d == 0 & c > 0 & flagm == "X" THEN mot = zun WHEN d == 0 THEN if flagm \== "X" THEN mot = zun WHEN d == 8 THEN mot = zun WHEN d == 1 THEN mot = "ONZE" WHEN d == 7 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "ET ONZE" ELSE mot = "ET" zun WHEN d == 9 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "ONZE" ELSE mot = "ET" zun OTHERWISE mot = "ET" zun END END WHEN u == 2 THEN SELECT WHEN d == 1 THEN mot = "DOUZE" WHEN d == 7 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "DOUZE" ELSE mot = "DEUX" WHEN d == 9 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "DOUZE" ELSE mot = "DEUX" OTHERWISE mot = "DEUX" END WHEN u == 3 THEN SELECT WHEN d == 1 THEN mot = "TREIZE" WHEN d == 7 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "TREIZE" ELSE mot = "TROIS" WHEN d == 9 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "TREIZE" ELSE mot = "TROIS" OTHERWISE mot = "TROIS" END WHEN u == 4 THEN SELECT WHEN d == 1 THEN mot = "QUATORZE" WHEN d == 7 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "QUATORZE" ELSE mot = "QUATRE" WHEN d == 9 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "QUATORZE" ELSE mot = "QUATRE" OTHERWISE mot = "QUATRE" END WHEN u == 5 THEN SELECT WHEN d == 1 THEN mot = "QUINZE" WHEN d == 7 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "QUINZE" ELSE mot = "CINQ" WHEN d == 9 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "QUINZE" ELSE mot = "CINQ" OTHERWISE mot = "CINQ" END WHEN u == 6 THEN SELECT WHEN d == 1 THEN mot = "SEIZE" WHEN d == 7 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "SEIZE" ELSE mot = "SIX" WHEN d == 9 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN mot = "SEIZE" ELSE mot = "SIX" OTHERWISE mot = "SIX" END WHEN u == 7 THEN SELECT WHEN d == 1 THEN mot = "DIX SEPT" WHEN d == 7 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN DO IF flagt == 't' THEN mot = "DIX-SEPT" ELSE mot = "DIX SEPT" END ELSE mot = "SEPT" WHEN d == 9 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN DO IF flagt == 't' THEN mot = "DIX-SEPT" ELSE mot = "DIX SEPT" END ELSE mot = "SEPT" OTHERWISE mot = "SEPT" END WHEN u == 8 THEN SELECT WHEN d == 1 THEN mot = "DIX HUIT" WHEN d == 7 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN DO IF flagt == 't' THEN mot = "DIX-HUIT" ELSE mot = "DIX HUIT" END ELSE mot = "HUIT" WHEN d == 9 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN DO IF flagt == 't' THEN mot = "DIX-HUIT" ELSE mot = "DIX HUIT" ENd ELSE mot = "HUIT" OTHERWISE mot = "HUIT" END WHEN u == 9 THEN SELECT WHEN d == 1 THEN mot = "DIX NEUF" WHEN d == 7 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN DO IF flagt == 't' THEN mot = "DIX-NEUF" ELSE mot = "DIX HUIT" END ELSE mot = "NEUF" WHEN d == 9 THEN IF belgosuisse \== "b" & belgosuisse \== "B" THEN DO IF flagt == 't' THEN mot = "DIX-NEUF" ELSE mot = "DIX HUIT" END ELSE mot = "NEUF" OTHERWISE mot = "NEUF" END OTHERWISE END IF mot \== " " THEN DO IF flagt \== 't' THEN DO zon = phrase mot END ELSE DO zon = phrase || '-' || mot END phrase = zon flagt = '' END flagu = "" flagm = " " RETURN /* *********************************** */ err: phrase = num /* AS400 */ /* 'CHGDTAARA DTAARA(*LDA (201 328)) VALUE('''phrase''')' */ /* EXIT */ /* standard : */ SAY phrase PULL RETURN phrase /* **************************************************************************** COMMENTAIRES Variables : flagt : pour mettre le tiret au lieu d'espace si "quatre-vingt..." flagm : pour omettre le "un" devant "mille" si c'est ..001000 flagu : pour savoir si "un" a la fin du groupe (..11, ou ..81 etc... plur : gerer le pluriel ****************************************** VERSION 0.9.0 : 2002-05-09 VERSION 0.9.9 : 2002-06-01 - Optimisation : traitement commun partie entiere/partie decimale. - Nombres en quatre-vingt : separation par tirets et non pas espaces. - Gestion amelioree du pluriel de l'unite : - correction : pas de "s" ajoute si deja s ou x a la fin de l'unite. - test ameliore (mots en al et ail...). - plus besoin du 4eme parametre. VERSION 0.9.99 : 2002-10-04 - En cas d'erreur, retourne la valeur entree et non pas null. - Largeur des lignes limitee a 80 caracteres (facilite sur AS400). VERSION 0.9.999 : 2005-05-27 - Pluriels ameliores (ou...). VERSION 1.0.00 : 2026-08-22 - Fonctionne sur des nombres de 12 chiffres. - Optimisation. - Passage direct des paramètres. VERSION 2.0.00 : 2026-08-25 - Fonctionne sur des nombres de 15 chiffres. - Modification de l'ordre des paramètres. - Sortie au choix en caracteres majuscules ou minuscules. ****************************************** Reste a voir / TODO : - 891001333000555 donne HUIT CENT QUATRE-VINGT-ONZE MILLE UN MILLIARD TROIS etc. au lieu de HUIT CENT QUATRE-VINGT-ONZE MILLE UN MILLIARDS TROIS etc. - Nombres ordinaux (premier...). - Unites de mesure. - Gestion des féminins en al, exemple : commercia-norma-génia(le/les). ----------------------------------------- */