A parte do idioma em português é que complica a rotina mas tudo bem.
Como é que a gente faz o extenso de um valor?
primeira parte com a palavra reais, e segunda parte centavos
N reais e N centavos
FUNCTION ze_ExtensoDinheiro( nValor )
LOCAL cTxt := "", cStrValor, nInteiro, nDecimal
nValor := Abs( nValor )
cStrValor := Str( nValor, 18, 2 )
nInteiro := Val( Substr( cStrValor, 1, At( ".", cStrValor ) - 1 ) )
nDecimal := Val( Substr( cStrValor, At( ".", cStrValor ) + 1 ) )
IF nInteiro != 0 .OR. nDecimal == 0
cTxt += ze_ExtensoNumero( nInteiro ) + " " + iif( nInteiro == 1, "REAL", "REAIS" )
ENDIF
IF nDecimal != 0
IF nInteiro != 0
cTxt += " E "
ENDIF
cTxt += ze_ExtensoNumero( nDecimal ) + " " + iif( nDecimal == 1, "CENTAVO", "CENTAVOS" )
ENDIF
RETURN cTxt
E depois?
A gente separa em blocos de três, e acrescenta bilhão, milhão, mil, etc.
N bilhões, N milhões, N mil e N
O detalhe é que coloquei na rotina pra fazer de trás pra frente... vai fazendo até acabar.
E recursividade, sem FOR/NEXT.
STATIC FUNCTION ze_ExtensoNumero( nValor, nGrupo )
LOCAL cTxt := "", cStrValor, nCentena, nResto, cTxtGrupo := "", lNegativo
LOCAL aList := { "", "MIL", "MILHAO", "BILHAO", "TRILHAO", "QUATRILHAO", ;
"QUINTILHAO", "SEPTILHAO", "OCTILHAO", "NONILHAO", "DECILHAO" }
hb_Default( @nGrupo, 1 )
lNegativo := ( nValor < 0 )
nValor := Abs( nValor )
cStrValor := StrZero( nValor, 16 )
nCentena := Val( Right( cStrValor, 3 ) )
nResto := Val( Substr( cStrValor, 1, Len( cStrValor ) - 3 ) )
IF nCentena != 0
IF nCentena > 0
cTxtGrupo := aList[ nGrupo ]
IF nCentena > 1
cTxtGrupo := StrTran( cTxtGrupo, "LHAO", "LHOES" )
ENDIF
ENDIF
cTxt := ze_ExtensoCentena( nCentena ) + " " + cTxtGrupo
ENDIF
IF nResto != 0 .AND. nGrupo < Len( aList )
cTxt := ze_ExtensoNumero( nResto, nGrupo + 1 ) + " E " + cTxt
ENDIF
IF nGrupo == 1
IF nValor == 0
cTxt := "ZERO"
ENDIF
cTxt := iif( lNegativo, "*NEGATIVO* ", "" ) + AllTrim( cTxt )
ENDIF
RETURN cTxt
Aà vém o grupo de 3 números... 999
Como a gente faz? a gente vê 100, 200, pode ser CEM ou CENTO, ou duzentos, trezentos, ... e alguma coisa
A rotina pega esse primeiro número, e se o que sobra for diferente de zero, chama a de 2 números... 99
exemplo... duzentos e N, ela preenche o duzentos e chama a rotina de dezena pra preencher o N
STATIC FUNCTION ze_ExtensoCentena( nValor )
LOCAL aList := { "CENTO", "DUZENTOS", "TREZENTOS", "QUATROCENTOS", ;
"QUINHENTOS", "SEISCENTOS", "SETECENTOS", "OITOCENTOS", ;
"NOVECENTOS" }
LOCAL nCentena, nDezena, cTxt := ""
nCentena := Int( nValor / 100 )
nDezena := Mod( nValor, 100 )
IF nValor > 0
IF nCentena == 1 .AND. nDezena == 0
cTxt += "CEM"
ELSE
IF nCentena != 0
cTxt += aList[ nCentena ]
ENDIF
IF nDezena != 0
IF nCentena != 0
cTxt += " E "
ENDIF
cTxt += ze_ExtensoDezena( nDezena )
ENDIF
ENDIF
ENDIF
RETURN cTxt
Aà vém a dezena... se for até 19 tem descrição própria, senão é vinte e n, trinta e N, etc.
Ela preenche a primeira parte e chama a rotina de unidade para o N
STATIC FUNCTION ze_ExtensoDezena( nValor )
LOCAL aList := { "DEZ", "VINTE", "TRINTA", "QUARENTA", "CINQUENTA", "SESSENTA", ;
"SETENTA", "OITENTA", "NOVENTA" }
LOCAL cTxt := "", nDezena, nUnidade
IF nValor > 0
nDezena := Int( nValor / 10 )
nUnidade := Mod( nValor, 10 )
IF nValor < 20
cTxt += ze_ExtensoUnidade( nValor )
ELSE
cTxt += aList[ nDezena ]
IF nUnidade != 0
cTxt += " E " + ze_ExtensoUnidade( nUnidade )
ENDIF
ENDIF
ENDIF
RETURN cTxt
E finalmente a unidade.
STATIC FUNCTION ze_ExtensoUnidade( nValor )
LOCAL aList := { "UM", "DOIS", "TRES", "QUATRO", "CINCO", "SEIS", ;
"SETE", "OITO", "NOVE", "DEZ", "ONZE", "DOZE", "TREZE", ;
"QUATORZE", "QUINZE", "DEZESSEIS", "DEZESSETE", "DEZOITO", ;
"DEZENOVE" }
RETURN aList[ nValor ]
O que achei interessante é que parece o jeito "humano" de fazer.
Foi mais como ensinar o jeito humano ao computador, do que traduzir o jeito humano para o jeito do computador.
E é nisso que muito programador apanha.
O que inventam pra facilitar programação é justamente pra trazer esse jeito humano para o fonte.
Só que o programador fica pensando em computador, e não em humanos.
Achei legal o resultado. A parte mais chata, ou com mais código fonte, é mesmo acertar a parte de português.
milhão ou milhões? bom... se maior que 1 é milhões.
olhem lá o fonte, tá igual o texto... se maior que 1 é ..lhões.
IF nCentena > 1
cTxtGrupo := StrTran( cTxtGrupo, "LHAO", "LHOES" )
ENDIF