Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Trucos (https://www.clubdelphi.com/foros/forumdisplay.php?f=52)
-   -   Convertir números a letras por medio de una función recursiva (https://www.clubdelphi.com/foros/showthread.php?t=88708)

nlsgarcia 20-07-2015 17:03:23

Convertir números a letras por medio de una función recursiva
 
Club Delphi,

Revisen el siguiente código en Delphi:
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Memo1: TMemo;
    Button2: TButton;
    GroupBox1: TGroupBox;
    RadioButton1: TRadioButton;
    RadioButton2: TRadioButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// Convierte números a letras de forma recursiva
function NumbersToLetters(Number: Double; Centime : Boolean) : String;
const
  Digit: array[1..9] of String = ('Uno', 'Dos', 'Tres',
                                  'Cuatro', 'Cinco', 'Seis',
                                  'Siete', 'Ocho', 'Nueve');

  Numeral: array[11..19] of String = ('Once', 'Doce', 'Trece',
                                      'Catorce', 'Quince', 'Diez y Seis',
                                      'Diez y Siete', 'Diez y Ocho', 'Diez y Nueve');

  Tenths: array[1..9] of String = ('Diez', 'Veinte', 'Trienta',
                                   'Cuarenta', 'Cincuenta', 'Sesenta',
                                   'Setenta', 'Ochenta', 'Noventa');

  Hundreds : array[1..9] of String = ('Cien ', 'Docientos ', 'Trecientos ',
                                      'Cuatrocientos ', 'Quinientos ', 'Seicientos ',
                                      'Setecientos ', 'Ochocientos ', 'Novecientos ');

  Min = 1;
  Max = 4294967295;

  function RecursiveNumber(N: LongWord): String;
  begin

    case N of

      1..9:
      begin
         Result := Digit[N];
      end;

      11..19:
      begin
         Result := Numeral[N]
      end;

      10,20..99:
      begin
         if (N Mod 10) = 0 then
            Result := Tenths[N div 10] + RecursiveNumber(N mod 10)
         else
            Result := Tenths[N div 10] + ' y '  + RecursiveNumber(N mod 10);
      end;

      100..999:
      begin
        if (N = 100) or (N >= 200) then Result := Hundreds[N div 100] + RecursiveNumber(N mod 100);
        if (N > 100) and (N < 200) then Result := 'Ciento ' + RecursiveNumber(N mod 100);
      end;

      1000..999999:
      begin
         if (Number >= 1000) and (Number < 2000) then
            Result := 'Un Mil ' + RecursiveNumber(N mod 1000)
         else
            Result := RecursiveNumber(N div 1000) + ' Mil ' + RecursiveNumber(N mod 1000);
      end;

      1000000..999999999:
      begin
         if (Number >= 1000000) and (Number < 2000000) then
            Result := 'Un Millon ' + RecursiveNumber(N mod 1000000)
         else
            Result := RecursiveNumber(N div 1000000) + ' Millones ' + RecursiveNumber(N mod 1000000);
      end;

      1000000000..4294967295:
      begin
         if (Number >= 1000000000) and (Number < 2000000000) then
            Result := 'Un Millardo ' + RecursiveNumber(N mod 1000000)
         else
            Result := RecursiveNumber(N div 1000000000) + ' Millardos ' + RecursiveNumber(N mod 1000000000);
      end;

    end;

  end;

var
   F : String;

begin
  if (Number >= Min) and (Number <= Max) then
     begin
        Result := RecursiveNumber(Trunc(Number));
        F := FormatFloat('00',Frac(Number) * 100);
        if Centime then
           Result := Result +  ' con ' + RecursiveNumber(StrToInt(F)) + ' Centimos'
        else
           Result := Result +  ' con ' + F + '/100';
     end
  else
     Result := '-1';
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
   RadioButton1.Checked := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
   Number : Double;
begin
   if TryStrToFloat(Edit1.Text,Number) then
   begin
      if RadioButton1.Checked then
         Memo1.Text := NumbersToLetters(Number,True);

      if RadioButton2.Checked then
         Memo1.Text := NumbersToLetters(Number,False)
   end
   else
      MessageDlg('Error en formato de Número',mtError,[mbOK],0);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
   Edit1.Text := EmptyStr;
   Memo1.Clear;
   RadioButton1.Checked := True;
   Edit1.SetFocus;
end;

end.
El código anterior en Delphi 7 sobre Windows 7 Professional x32 permite : Convertir números a letras por medio de una función recursiva y escoger si los céntimos son visualizados como letras o fracción, como se muestra en la siguiente imagen:



El código del ejemplo esta disponible en : NumbersToLetters.rar

Espero sea útil :)

Nelson.

Casimiro Notevi 20-07-2015 17:11:17

"con 99/100"
¿Eso dónde se usa?

nlsgarcia 20-07-2015 17:16:02

Casimiro,

Cita:

Empezado por Casimiro
..."con 99/100" ¿Eso dónde se usa?...

En Venezuela se usa al momento de hacer un cheque manualmente, es una forma de abreviar los céntimos.

Saludos,

Nelson.

Casimiro Notevi 20-07-2015 17:25:27

Cita:

Empezado por nlsgarcia (Mensaje 494636)
es una forma de abreviar los céntimos

Pues diría que no abrevia nada, sino todo lo contrario:
Código:

,99
99/100


nlsgarcia 20-07-2015 17:36:02

Casimiro,

Cita:

Empezado por Casimiro
...no abrevia nada, sino todo lo contrario...

:rolleyes:

Abrevia con respecto a la conversión de números a letras como se puede observar en la imagen del Msg #1.

Saludos,

Nelson.

Casimiro Notevi 20-07-2015 17:46:37

Ya, claro, pero es que entonces no ha sido convertido a letras :)

Casimiro Notevi 20-07-2015 17:48:02

Que no digo que esté mal el conversor, está muy bien, es cortito, pocas línes y muy claro. ^\||/
Tan solo que me ha llamado la atención eso del 99/100

egostar 20-07-2015 17:55:36

Cita:

Empezado por Casimiro Notevi (Mensaje 494635)
"con 99/100"
¿Eso dónde se usa?

En México se usa y representa los céntimos de un peso los cuales no se convierten a letra. En términos legales cualquier cantidad expresada en letra (normalmente cheques y facturas) y que llevan cantidad en letra se deben escribir con el formato de Pesos con letra, los centavos representados por la fracción de 100, más las letras M.N. (Moneda Nacional).

De tal forma que la cantidad

$1,250.35

se escribe así:

Un Mil Docientos Cincuenta Pesos 35/100 M.N.

Saludos

Casimiro Notevi 20-07-2015 18:04:24

Curioso.
:)

Neftali [Germán.Estévez] 20-07-2015 18:42:15

Estaría bien subirlo al FTP, junto con el ejemplo.


Ah!!!! y gracias por compartirlo. ^\||/

Al González 20-07-2015 20:34:36

Cita:

Empezado por egostar (Mensaje 494642)
En México se usa y representa los céntimos de un peso los cuales no se convierten a letra. En términos legales cualquier cantidad expresada en letra (normalmente cheques y facturas) y que llevan cantidad en letra se deben escribir con el formato de Pesos con letra, los centavos representados por la fracción de 100, más las letras M.N. (Moneda Nacional).

Eliseo lo ha explicado muy bien. :)

Me permito algunos comentarios sobre lo expuesto hasta ahora por los compañeros.

Es más correcto escribir doscientos que docientos. Y además deben evitarse las letras mayúsculas iniciales, con excepción de la primera palabra cuando sea inicio de enunciado. En español, y más concretamente en castellano, los números y las monedas, así como los adjetivos gentilicios, los nombres de los días de la semana, los meses y las estaciones del año, no deben iniciar con letra mayúscula (con la salvedad antes mencionada).

Adicionalmente, el un para decir un mil es opcional. Aparentemente se acostumbraba agregar el un para dificultar la alteración fraudulenta de documentos (cheques que podrían pasar de "mil trescientos..." a "ocho mil trescientos...", por ejemplo).

Por otro lado, Nelson, debes revisar tu función. Falta el acento en millon y centimos, hay erratas en varios centenarios (por ejemplo falta la ese en seicientos) y otras cantidades no están del todo bien, como "diez y seis", que para expresar cantidades con letra debería ser dieciséis.

Ahora, una recomendación de programador bibliotecario. Cuando creen este tipo de funciones, intenten ver más allá de la necesidad inmediata que desean resolver. Una gran función (o método) que convierte cantidades monetarias a su expresión con letra puede ser dividida en dos o más funciones que le den más utilidad al código. Por ejemplo, pueden crear una función que sirva para convertir cualquier número entero a su expresión con letras, y luego crear una segunda función que sirva para convertir cualquier cantidad monetaria (número decimal) a su expresión con letras. Entonces hacer que la segunda función se apoye llamando a la primera función.

Yendo más allá, a la primera función pueden agregarle un parámetro para indicar género (masculino, femenino y neutro). Y con ello podrán expresar con letra prácticamente cualquier cantidad que así deba aparecer en algún documento (cuadernos, paellas, etc.), sin limitar un código tan valioso para servir solamente con dinero.

Reciban un cordial saludo. :)

nlsgarcia 20-07-2015 20:40:13

German,

Cita:

Empezado por Neftali
...Estaría bien subirlo al FTP...

:rolleyes:

En el Msg #1 hay un link al FTP del Club Delphi para descargar el código del ejemplo y su ejecutable.

Saludos,

Nelson.

Casimiro Notevi 20-07-2015 21:11:56

Cita:

Empezado por Al González (Mensaje 494648)
Reciban un cordial saludo. :)

^\||/^\||/^\||/

egostar 20-07-2015 21:21:44

Cita:

Empezado por Al González (Mensaje 494648)
Es más correcto escribir doscientos que docientos.

Anotado.

Cita:

Empezado por Al González (Mensaje 494648)
Y además deben evitarse las letras mayúsculas iniciales

Algunos vicios que tiene uno :), de hecho normalmente las cantidades en letra no las escribo con minúsculas, todo en mayúsculas. De cualquier forma, anotado.

Cita:

Empezado por Al González (Mensaje 494648)
Adicionalmente, el un para decir un mil es opcional.

Así es, es opcional, igual que el "Son" ( Son dos mil ...... ) que se usa/usaba en los cheques, algo que ya está en franco "desuso" debido a la popularidad de las transacciones en línea y/o pagos a través de tarjetas.

Saludos

nlsgarcia 20-07-2015 21:29:20

Al,

Cita:

Empezado por Al
...Es más correcto escribir doscientos que docientos...

Es correcto ^\||/ , igual aplica para trescientos y seiscientos.

Cita:

Empezado por Al
...deben evitarse las letras mayúsculas iniciales, con excepción de la primera palabra...

Es correcto ^\||/ , sin embargo en este caso es por seguridad, resalta más las cifras.

Cita:

Empezado por Al
...el un para decir un mil es opcional...

Es correcto ^\||/ , sin embargo en este caso es por seguridad, evita alteraciones al cheque en cifras entre 1000 y 1999.

Cita:

Empezado por Al
...Falta el acento en millón y céntimos...falta la ese en seiscientos...

Es correcto ^\||/

Cita:

Empezado por Al
...otras cantidades no están del todo bien, como "diez y seis"...

Es correcto ^\||/ , sin embargo en este caso es por seguridad, resalta más las cifras.

Cita:

Empezado por Al
...una recomendación de programador bibliotecario...

^\||/

Saludos,

Nelson.

nlsgarcia 21-07-2015 04:35:06

Club Delphi,

Revisen el siguiente código:
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    rdgCentime: TRadioGroup;
    rdgCapital: TRadioGroup;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// Convierte números a letras de forma recursiva
{
 Number : Número a convertir en letras, puede ser con o sin décimales
 Centime : 0 = Céntimos a Letras, 1 = Céntimos a Fracción, 2 = Sin Céntimos, valor por default 0
 Capital : 0 = Al inicio de cada Número, 1 = Solo el primer Número, 2 = Todo, valor por default 0
}
function NumbersToLetters(Number: Double; Centime : Byte = 0; Capital : Byte = 0) : String;
const
  Digit: Array[1..9] of String = ('Uno', 'Dos', 'Tres',
                                  'Cuatro', 'Cinco', 'Seis',
                                  'Siete', 'Ocho', 'Nueve');

  Numeral: Array[11..19] of String = ('Once', 'Doce', 'Trece',
                                      'Catorce', 'Quince', 'Diez y Seis',
                                      'Diez y Siete', 'Diez y Ocho', 'Diez y Nueve');

  Tenths: Array[1..9] of String = ('Diez', 'Veinte', 'Trienta',
                                   'Cuarenta', 'Cincuenta', 'Sesenta',
                                   'Setenta', 'Ochenta', 'Noventa');

  Hundreds : Array[1..9] of String = ('Cien ', 'Doscientos ', 'Trescientos ',
                                      'Cuatrocientos ', 'Quinientos ', 'Seiscientos ',
                                      'Setecientos ', 'Ochocientos ', 'Novecientos ');

  Min = 1;
  Max = 4294967295;

  function RecursiveNumber(N: LongWord): String;
  begin

    case N of

      1..9:
      begin
         Result := Digit[N];
      end;

      11..19:
      begin
         Result := Numeral[N]
      end;

      10,20..99:
      begin
         if (N Mod 10) = 0 then
            Result := Tenths[N div 10] + RecursiveNumber(N mod 10)
         else
            Result := Tenths[N div 10] + ' y '  + RecursiveNumber(N mod 10);
      end;

      100..999:
      begin
        if (N = 100) or (N >= 200) then Result := Hundreds[N div 100] + RecursiveNumber(N mod 100);
        if (N > 100) and (N < 200) then Result := 'Ciento ' + RecursiveNumber(N mod 100);
      end;

      1000..999999:
      begin
         if (Number >= 1000) and (Number < 2000) then
            Result := 'Un Mil ' + RecursiveNumber(N mod 1000)
         else
            Result := RecursiveNumber(N div 1000) + ' Mil ' + RecursiveNumber(N mod 1000);
      end;

      1000000..999999999:
      begin
         if (Number >= 1000000) and (Number < 2000000) then
            Result := 'Un Millón ' + RecursiveNumber(N mod 1000000)
         else
            Result := RecursiveNumber(N div 1000000) + ' Millones ' + RecursiveNumber(N mod 1000000);
      end;

      1000000000..4294967295:
      begin
         if (Number >= 1000000000) and (Number < 2000000000) then
            Result := 'Un Millardo ' + RecursiveNumber(N mod 1000000)
         else
            Result := RecursiveNumber(N div 1000000000) + ' Millardos ' + RecursiveNumber(N mod 1000000000);
      end;

    end;

  end;

var
   F : String;
   NumberStr : String;

begin

  if (Number >= Min) and (Number <= Max) then
  begin

     NumberStr := Trim(RecursiveNumber(Trunc(Number)));
     F := FormatFloat('00',Frac(Number) * 100);

     case Centime of
        0 : if F = '00' then
               NumberStr := NumberStr +  ' con ' + 'Cero Céntimos'
            else
               NumberStr := NumberStr +  ' con ' + RecursiveNumber(StrToInt(F)) + ' Céntimos';

        1 : NumberStr := NumberStr +  ' con ' + F + '/100';

        2 : F := EmptyStr;
     end;

     case Capital of
        0 : Result := NumberStr;

        1 : Result := Uppercase(Copy(NumberStr,1,1))+Lowercase(Copy(NumberStr,2,Length(NumberStr)));

        2 : begin
               NumberStr := StringReplace(NumberStr,'Millón','Millon',[]);
               NumberStr := StringReplace(NumberStr,'Céntimos','Centimos',[]);
               Result := Uppercase(NumberStr);
            end;
     end;

  end
  else
     Result := '-1';

end;

procedure TForm1.FormCreate(Sender: TObject);
var
   i : Integer;
begin
   rdgCentime.Font.Color := clBlue;
   rdgCapital.Font.Color := clBlue;
   for i := 0 to  rdgCentime.ControlCount -1 do
   begin
      TRadioButton(rdgCentime.Controls[i]).Font.Color := clBlack;
      TRadioButton(rdgCapital.Controls[i]).Font.Color := clBlack;
   end;
   rdgCentime.ItemIndex := 0;
   rdgCapital.ItemIndex := 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
   Number : Double;
begin
   if TryStrToFloat(Edit1.Text,Number) then
      Memo1.Text := NumbersToLetters(Number,rdgCentime.ItemIndex, rdgCapital.ItemIndex)
   else
      MessageDlg('Error en formato de Número',mtError,[mbOK],0);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
   Edit1.Text := EmptyStr;
   Memo1.Clear;
   rdgCentime.ItemIndex := 0;
   rdgCapital.ItemIndex := 0;
   Edit1.SetFocus;
end;

end.
El código anterior en Delphi 7 sobre Windows 7 Professional x32 es la Versión 2 del código propuesto en el Msg #1, el cual permite : Convertir números a letras por medio de una función recursiva y escoger entre tres opciones de céntimos y mayúsculas, como se muestra en la siguiente imagen:



El código del ejemplo esta disponible en : NumbersToLetters_v2.rar

Notas:

1- Esta versión es más adaptable a diferentes requerimientos.

2- La función mantiene la simplicidad de la original.

3- Se corrigieron algunas erratas y detalles menores.

Espero sea útil :)

Nelson.

ElKurgan 21-07-2015 08:32:26

Gracias a todos por compartir sus conocimientos

ecfisa 22-07-2015 04:43:03

Muchas gracias por el aporte Nelson ^\||/

Saludos :)


La franja horaria es GMT +2. Ahora son las 10:59:12.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi