ATOUTFOX
COMMUNAUTÉ FRANCOPHONE DES PROFESSIONNELS FOXPRO
Visual FoxPro : le développement durable

cConstantNum() - Constante numérique d'après une chaine de caractères représentant un nombre   



L'auteur

FoxInCloud (Th. Nivelet)
France France
Membre Simple
# 0000000014
enregistré le 13/10/2004

http://www.foxincloud.com/
Nivelet Thierry
75016 Paris
de la société Abaque
Fiche personnelle


Note des membres
pas de note

Contributions > 01 - PRG : Programmation > Conversions

cConstantNum() - Constante numérique d'après une chaine de caractères représentant un nombre
# 0000000160
ajouté le 11/03/2005 09:17:25 et modifié le 30/03/2005
consulté 11011 fois
Niveau initié

Version(s) Foxpro :
VFP 9.0
VFP 8.0
VFP 7.0
VFP 6.0
VFP 5.0

Description

Avec FoxPro on ne sait pas toujours à quel séparateur décimal se vouer ... le séparateur courant (set('POINT')) ou le point '.' (period) ?

  • Val() attend le séparateur décimal courant (virgule en général pour les francophones)
  • Les calculs, et alter column de caractère à numérique, attendent une constante nombre, avec le point pour séparateur décimal (period)

Pour nous qui, en général, utilisons la virgule comme séparateur décimal, la conversion de caractère à numérique est un petit casse-tête.

La fonction cConstantNum() affranchit de ces subtilités encombrantes.

Elle est livrée avec lNumber(). lNumber() vérifie qu'une chaine de caractère est valide pour représenter un nombre.

Code source :
FUNCTION cConstantNum && Constante numérique d'après une chaine de caractères représentant un nombre
 LPARAMETERS ;
  tcNum,; && Chaine de caractères supposée représenter un nombre
  tlPeriod && [.F.] séparateur décimal point (.F.: courant) [Val() veut courant, calcul et ALTER COLUMN veulent point]
 LOCAL lcResult
 m.lcResult = Space(0)

 * Si le paramètre est de type caractère
 LOCAL llResult
 m.llResult = Vartype(m.tcNum) == 'C'
 ASSERT m.llResult MESSAGE Program() + Space(1) + "Paramètre de type caractère attendu"
 IF m.llResult

  * Si le paramètre peut représenter un nombre
  m.llResult = lNumber(m.tcNum)
  IF m.llResult

   * Supprimer les espaces et séparateurs de milliers éventuels
   LOCAL lcNum, lcSep, lcPoint
   m.lcNum = Alltrim(m.tcNum)
   m.lcSep = Set('Separator')
   m.lcPoint = Set('Point')
   m.lcNum = Iif(m.lcSep == m.lcPoint, m.lcNum, Chrtran(m.lcNum, m.lcSep, Space(0)))
   m.lcNum = Chrtran(m.lcNum, Space(1), Space(0))

   * Lire si séparateur décimal POINT demandé
   LOCAL llPeriod
   m.llPeriod = Iif(Vartype(m.tlPeriod) == 'L', m.tlPeriod, .F.)

   * Si la chaine comporte au plus un séparateur décimal
   LOCAL llPoint, lnPoints, lnPeriods
   m.llPoint = m.lcPoint == '.'
   m.lnPoints = Occurs(m.lcPoint, m.lcNum)
   m.lnPeriods = Iif(m.llPoint, 0, Occurs('.', m.lcNum))
   m.llResult = m.lnPoints + m.lnPeriods <= 1
   IF m.llResult

    * Si le séparateur courant n'est pas le point
    IF NOT m.llPoint

     * Ajuster le séparateur si nécessaire
     DO CASE
     CASE m.llPeriod AND m.lnPoints = 1
      m.lcNum = Chrtran(m.lcNum, m.lcPoint, '.')
     CASE NOT m.llPeriod AND m.lnPeriods = 1
      m.lcNum = Chrtran(m.lcNum, '.', m.lcPoint)
     ENDCASE
    ENDIF
    m.lcResult = m.lcNum
   ENDIF
  ENDIF
 ENDIF

 RETURN m.lcResult

* -----------
 FUNCTION lNumber && Chaine de caractères représente un nombre
 LPARAMETERS ;
  tcChain && Chaine à vérifier
 LOCAL llResult

 * Si la chaine est correcte
 IF Vartype(m.tcChain) == 'C' ;
  AND NOT Empty(m.tcChain)

  * Définir les caractères non numériques possibles
  LOCAL lcSeps
  m.lcSeps = Set("Point") + Set("Separator") + [ .+-]

  * Vérifier chaque caractère de la chaine
  LOCAL lcChain, lnChar, lcChar
   m.lcChain = Alltrim(m.tcChain)
  FOR m.lnChar = 1 TO Len(m.lcChain)
   m.lcChar = Substr(m.lcChain, m.lnChar, 1)
   m.llResult = ;
    IsDigit(m.lcChar) ;
    OR m.lcChar $ m.lcSeps
   IF NOT m.llResult
    EXIT
   ENDIF
  ENDFOR
 ENDIF

 RETURN m.llResult
Commentaires
le 12/03/2005, eddymaue a écrit :
func cConstantNum ( tcNum) && Chaine de caractères supposée représenter un nombre
RETURN CHRTRAN(TRANSFORM(tcNum),IIF(SET("point")=".",",","."),SET("point"))


le 14/03/2005, FoxInCloud (Th. Nivelet) a écrit :
cConstantNum() dépasse précisément les limites de cette formule.
Th N

le 15/03/2005, eddymaue a écrit :
Je ne faisais que répondre à la question initiale et à son objectif. Et je te cite

Avec FoxPro on ne sait pas toujours à quel séparateur décimal se vouer ... le séparateur courant (set('POINT')) ou le point '.' (period) ?

Pour ce qui est du reste. Si les données sont extraites d'une page html je comprend. Si non c'est que les entrées ne sont pas formatées.

Comme par exemple #####.## et ou 9999.99 imposés dans un contrôle d'entré. Textbox, Editbox et autres.

Autrement dit. On force l'utilisateur à utiliser un format prédéterminé.

À ce moment là, ça devient inutile d'essayer de trouver des caractères non numériques.

Reste tourjours le "-","+" et le "%" dans un champ caractère et ou toute ambiguïté est éliminée par EMPTY(cConstantNum,CHRTRAN,"0123456789%-+",""))=.t. que je validerais en entré.
En ce qui me concerne, ta fonction est défensive et si le problème se pose alors là c'est la structure même du programme qui est à revoir.

Au plaisir d'en discuter et d'en approfondir le sujet.

Eddy a+

le 15/03/2005, FoxInCloud (Th. Nivelet) a écrit :
Merci pour ce cours magistral.
Tu sembles connaître les manies de tous les utilisateurs, sauf les miens.
Pour ce qui est de la structure du programme, la mienne me convient parfaitement.
Merci en tous cas de ta contribution positive et flatteuse.
Th N



www.atoutfox.org - Site de la Communauté Francophone des Professionnels FoxPro - v3.4.0 - © 2004-2024.
Cette page est générée par un composant COM+ développé en Visual FoxPro 9.0-SP2-HF3