Clipper On Line • Ver Tópico - Rotina de Extenso

Rotina de Extenso

Aqui você poderá oferecer suas Contribuições, Dicas e Tutoriais (Texto ou Vídeo) que sejam de interesse de todos.

Moderador: Moderadores

 

Rotina de Extenso

Mensagempor JoséQuintas » 21 Jul 2019 17:26

Refiz minha rotina de extenso de valor, mas ficou interessante.... parece mais .... humana
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
José M. C. Quintas
Harbour 3.4, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, hbnetio, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
Avatar de usuário

JoséQuintas
Colaborador

Colaborador
 
Mensagens: 11906
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 12 vezes
Mens.Curtidas: 759 vezes

Rotina de Extenso

Mensagempor JoséQuintas » 21 Jul 2019 17:29

E a parte legal de separar os números, é que dá pra usar numa rotina de extenso de data, por exemplo.

   ELSEIF ValType( xValue ) == "D"
      IF ! xFull
         cTxt := StrZero( Day( xValue ), 2 ) + " DE " + ze_ExtensoMes( xValue ) + " DE " + StrZero( Year( xValue ), 4 )
      ELSE
         cTxt := ze_ExtensoNumero( Day( xValue ) )
         cTxt += " DE " + ze_ExtensoMes( xValue ) + " DE "
         cTxt += ze_ExtensoNumero( Year( xValue ) )
         DO WHILE Space(2) $ cTxt
            cTxt := StrTran( cTxt, Space(2), Space(1) )
         ENDDO
      ENDIF
   ENDIF
José M. C. Quintas
Harbour 3.4, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, hbnetio, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
Avatar de usuário

JoséQuintas
Colaborador

Colaborador
 
Mensagens: 11906
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 12 vezes
Mens.Curtidas: 759 vezes




Retornar para Contribuições, Dicas e Tutoriais

Quem está online

Usuários vendo este fórum: Ahrefs [Bot] e 2 visitantes


Ola Amigo, espero que meu site e forum tem lhe beneficiado, com exemplos e dicas de programacao.
Entao divulgue o link da Doacao abaixo para seus amigos e redes sociais ou faça uma doacao para o site forum...
MUITO OBRIGADO PELA SUA DOACAO!
Faça uma doação para o forum
v
Olá visitante, seja bem-vindo ao Fórum Clipper On Line!
Efetue o seu login ou faça o seu Registro