Fazer um recibo ou cheque de pagamento com o valor por extenso, emitir uma nota fiscal de venda apresentando o total do documento por extenso, são alguns exemplos de situações que sugerem a necessidade de uma aplicação comercial para definir um valor monetário em reais por extenso.

Este artigo tem como objetivo demonstrar os passos necessários para construir uma aplicação Delphi para definir um valor por extenso.

Primeiramente deve-se criar uma aplicação no ambiente de desenvolvimento Delphi 7 através da opção do menu "File|New|Application..." e implementar os seguintes passos:

1º Passo:

Desenvolver o formulário principal como sugere a Figura 1. Atenção: observe que as caixas de textos explicativos utilizadas na figura apresentam a ordem sequencial e o nome do componente, a página da sua localização e as propriedades que devem ser alteradas com os respectivos valores.

Formulário principal da aplicação
Figura 1. Formulário principal da aplicação.

2º Passo:

Implementar em uma unidade de códigos (unit) construída através da opção do menu "File|New|Unit" o subprograma "valorPorExtenso", como apresentado na Listagem 1. Salvar o arquivo fonte da unit implementada com o nome "Um".

Listagem 1. Unit com a função "valorPorExtenso".
unit Um;

interface
function valorPorExtenso(vlr: real): string;

implementation
uses SysUtils;

function valorPorExtenso(vlr: real): string;
const
  unidade: array[1..19] of string = ('um', 'dois', 'três', 'quatro', 'cinco',
             'seis', 'sete', 'oito', 'nove', 'dez', 'onze',
             'doze', 'treze', 'quatorze', 'quinze', 'dezesseis',
             'dezessete', 'dezoito', 'dezenove');
  centena: array[1..9] of string = ('cento', 'duzentos', 'trezentos',
             'quatrocentos', 'quinhentos', 'seiscentos',
             'setecentos', 'oitocentos', 'novecentos');
  dezena: array[2..9] of string = ('vinte', 'trinta', 'quarenta', 'cinquenta',
             'sessenta', 'setenta', 'oitenta', 'noventa');
  qualificaS: array[0..4] of string = ('', 'mil', 'milhão', 'bilhão', 'trilhão');
  qualificaP: array[0..4] of string = ('', 'mil', 'milhões', 'bilhões', 'trilhões');
var
                        inteiro: Int64;
                          resto: real;
  vlrS, s, saux, vlrP, centavos: string;
     n, unid, dez, cent, tam, i: integer;
                    umReal, tem: boolean;
begin
  if (vlr = 0)
     then begin
            valorPorExtenso := 'zero';
            exit;
          end;

  inteiro := trunc(vlr); // parte inteira do valor
  resto := vlr - inteiro; // parte fracionária do valor
  vlrS := inttostr(inteiro);
  if (length(vlrS) > 15)
     then begin
            valorPorExtenso := 'Erro: valor superior a 999 trilhões.';
            exit;
          end;

  s := '';
  centavos := inttostr(round(resto * 100));

// definindo o extenso da parte inteira do valor
  i := 0;
  umReal := false; tem := false;
  while (vlrS <> '0') do
  begin
    tam := length(vlrS);
// retira do valor a 1a. parte, 2a. parte, por exemplo, para 123456789:
// 1a. parte = 789 (centena)
// 2a. parte = 456 (mil)
// 3a. parte = 123 (milhões)
    if (tam > 3)
       then begin
              vlrP := copy(vlrS, tam-2, tam);
              vlrS := copy(vlrS, 1, tam-3);
            end
    else begin // última parte do valor
           vlrP := vlrS;
           vlrS := '0';
         end;
    if (vlrP <> '000')
       then begin
              saux := '';
              if (vlrP = '100')
                 then saux := 'cem'
              else begin
                     n := strtoint(vlrP);        // para n = 371, tem-se:
                     cent := n div 100;          // cent = 3 (centena trezentos)
                     dez := (n mod 100) div 10;  // dez  = 7 (dezena setenta)
                     unid := (n mod 100) mod 10; // unid = 1 (unidade um)
                     if (cent <> 0)
                        then saux := centena[cent];
                     if ((dez <> 0) or (unid <> 0))
                        then begin
                               if ((n mod 100) <= 19)
                                  then begin
                                         if (length(saux) <> 0)
                                            then saux := saux + ' e ' + unidade[n mod 100]
                                         else saux := unidade[n mod 100];
                                       end
                               else begin
                                      if (length(saux) <> 0)
                                         then saux := saux + ' e ' + dezena[dez]
                                      else saux := dezena[dez];
                                      if (unid <> 0)
                                         then if (length(saux) <> 0)
                                                 then saux := saux + ' e ' + unidade[unid]
                                              else saux := unidade[unid];
                                    end;
                             end;
                   end;
              if ((vlrP = '1') or (vlrP = '001'))
                 then begin
                        if (i = 0) // 1a. parte do valor (um real)
                           then umReal := true
                        else saux := saux + ' ' + qualificaS[i];
                      end
              else if (i <> 0)
                      then saux := saux + ' ' + qualificaP[i];
              if (length(s) <> 0)
                 then s := saux + ', ' + s
              else s := saux;
            end;
    if (((i = 0) or (i = 1)) and (length(s) <> 0))
       then tem := true; // tem centena ou mil no valor
    i := i + 1; // próximo qualificador: 1- mil, 2- milhão, 3- bilhão, ...
  end;

  if (length(s) <> 0)
     then begin
            if (umReal)
               then s := s + ' real'
            else if (tem)
                    then s := s + ' reais'
                 else s := s + ' de reais';
          end;
// definindo o extenso dos centavos do valor
  if (centavos <> '0') // valor com centavos
     then begin
            if (length(s) <> 0) // se não é valor somente com centavos
               then s := s + ' e ';
            if (centavos = '1')
               then s := s + 'um centavo'
            else begin
                   n := strtoint(centavos);
                   if (n <= 19)
                      then s := s + unidade[n]
                   else begin                 // para n = 37, tem-se:
                          unid := n mod 10;   // unid = 37 % 10 = 7 (unidade sete)
                          dez := n div 10;    // dez  = 37 / 10 = 3 (dezena trinta)
                          s := s + dezena[dez];
                          if (unid <> 0)
                             then s := s + ' e ' + unidade[unid];
                       end;
                   s := s + ' centavos';
                 end;
          end;
  valorPorExtenso := s;
end;

end.

As unidades ou bibliotecas de códigos (unit's) representam no Delphi a forma de disponibilizar um conjunto de subprogramas (functions e/ou procedures) destinados a solucionar uma série de tarefas bastante corriqueiras, como por exemplo, a função para definir o valor por extenso. Na Listagem 2 pode-se observar a estrutura básica de uma unit.

Listagem 2. Estrutura básica de uma unit.
// Cabeçalho da unidade de códigos.
// Atenção: O nome interno da unit deve ser o mesmo nome dado ao arquivo fonte
unit NomeDaUnit;

interface
// Comunicação entre dois meios (dispositivos). Contêm o cabeçalho
// dos procedimentos e funções declarados na unit, declaração
// de objetos globais e o uso de outras unidades.

implementation
// Corpo dos procedimentos e funções anunciados na seção de
// interface e declarações de objetos locais.
end.

Outro aspecto destacável da programação foi a utilização da estrutura de controle de erros "try – except - end" que irá proteger o código para eventuais erros de conversão de tipo com as funções "StrToFloat" e "StrToInt".

3º Passo:

Agora novamente no formulário principal deve-se:

  • Fazer a referência a unit "Um", implementada no passo 2, através da opção do menu "File|Use Unit...". A conclusão deste passo resulta na seguinte linha de código:

    uses Um;
  • Implementar o seguinte código no evento "onClick" do botão "Extenso do Valor": Memo1.Clear;

    try
      Memo1.Lines.Add(valorPorExtenso(StrToFloat(Edit1.Text)));
    except
    end;

O algoritmo para resolver o problema do "valor por extenso" acaba de alguma forma apresentando uma solução complexa uma vez que várias situações devem ser previstas, por exemplo:

  • qualificadores do valor no singular (qualificaS) e no plural (qualificaP): milhão e milhões, bilhão e bilhões;
  • valores com tratamento diferenciado: um real, cinco reais, cem mil reais, cento e cinco milhões de reais;
  • extenso da parte inteira do valor e da parte fracionária definidos separadamente;
  • limitação do valor monetário de entrada a 999 trilhões.

Veja também: Valor por Extenso em uma Aplicação Java.

Ilustrando a execução da aplicação:

trinta e nove centavos um real e vinte e nove centavos cento e vinte três reais e sessenta e dois centavos cinquenta e quatro milhôes, trezentos e quarenta mil, duzentos e dez reais e trinta e um centavos