25 abr 2011

Convertir Número a Letras en C#

Cuando se realizan trabajos donde se necesita mostrar al cliente un determinado monto de dinero, tipo factura, recibo, cheque, etc, el cliente desea ver el monto en numeral asi como en literal.

Por ejemplo:

877866,50 = ochocientos setenta y siete mil ochocientos sesenta y seis 50/100 Bolivianos
Pues bien, la siguiente clase a la que llame NumLetra.cs realiza justamente esa operacion, esta extracomentada y trate de hacerla lo mas entendible posible. El proyecto en C#, lo llame con_NumLetraC

La logica que se utliza es la siguiente:

La clase recibe un numero ej. 123456789,50
valida este numero, si el numero no es valido devuelve NULL
Si el numero es valido segun sea este unidad, decena, centena, mil o millon,  va clasificando el numero y llama a sus procedimientos correspondientes, estas funciones, son utilizadas en cascada, osea:
nuestro numero de ejemplo es 123456789,50, entonces separa en 123456789 y 50, siendo 50 nuestra parte decimal.

El  numero entero, 123456789 es clasificado = es millon, entonces llama a la funcion getMillones, esta funcion a la vez divide el numero en miles y millones
123456789 = 123 456789 donde 123 corresponde a millones y 456789 a miles
entonces la misma funcion llama a las funciones getMiles, getCentenas, getUnidades, segun corresponda, al igual que la funcion getMiles, hace uso de getCentenas, getDecenas getUnidades, lo mismo getCentenas, hace uso de getDececas, getUnidades.

Espero se entienda :)


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace con_NumLetraC
{
    class NumLetra
    {
        private String[] UNIDADES = { "", "un ", "dos ", "tres ", "cuatro ", "cinco ", "seis ", "siete ", "ocho ", "nueve " };
        private String[] DECENAS = {"diez ", "once ", "doce ", "trece ", "catorce ", "quince ", "dieciseis ",
        "diecisiete ", "dieciocho ", "diecinueve", "veinte ", "treinta ", "cuarenta ",
        "cincuenta ", "sesenta ", "setenta ", "ochenta ", "noventa "};
        private String[] CENTENAS = {"", "ciento ", "doscientos ", "trecientos ", "cuatrocientos ", "quinientos ", "seiscientos ",
        "setecientos ", "ochocientos ", "novecientos "};

        private Regex r;
    
        public String Convertir(String numero, bool mayusculas) {
            
        String literal = "";
        String parte_decimal;    
        //si el numero utiliza (.) en lugar de (,) -> se reemplaza
        numero = numero.Replace(".", ",");
            
        //si el numero no tiene parte decimal, se le agrega ,00
        if(numero.IndexOf(",")==-1){            
            numero = numero + ",00";
        } 
        //se valida formato de entrada -> 0,00 y 999 999 999,00
        r = new Regex(@"\d{1,9},\d{1,2}");            
        MatchCollection mc = r.Matches(numero);
        if (mc.Count > 0) {
            //se divide el numero 0000000,00 -> entero y decimal
            String[] Num = numero.Split(',');                    
            
            //de da formato al numero decimal
            parte_decimal = Num[1] + "/100 Bolivianos.";
            //se convierte el numero a literal
            if (int.Parse(Num[0]) == 0) {//si el valor es cero                
                literal = "cero ";
            }
            else if (int.Parse(Num[0]) > 999999)
            {//si es millon
                literal = getMillones(Num[0]);
            }
            else if (int.Parse(Num[0]) > 999)
            {//si es miles
                literal = getMiles(Num[0]);
            }
            else if (int.Parse(Num[0]) > 99)
            {//si es centena
                literal = getCentenas(Num[0]);
            }
            else if (int.Parse(Num[0]) > 9)
            {//si es decena
                literal = getDecenas(Num[0]);
            } else {//sino unidades -> 9
                literal = getUnidades(Num[0]);
            }
            //devuelve el resultado en mayusculas o minusculas
            if (mayusculas) {                
                return (literal + parte_decimal).ToUpper();
            } else {
                return (literal + parte_decimal);
            }
        } else {//error, no se puede convertir
            return literal = null;
        }
    }
    
        /* funciones para convertir los numeros a literales */

        private String getUnidades(String numero)
        {   // 1 - 9            
            //si tuviera algun 0 antes se lo quita -> 09 = 9 o 009=9
            String num = numero.Substring(numero.Length - 1);            
            return UNIDADES[int.Parse(num)];
        }

        private String getDecenas(String num)
        {// 99                        
            int n = int.Parse(num);
            if (n < 10)
            {//para casos como -> 01 - 09
                return getUnidades(num);
            }
            else if (n > 19)
            {//para 20...99
                String u = getUnidades(num);
                if (u.Equals(""))
                { //para 20,30,40,50,60,70,80,90
                    return DECENAS[int.Parse(num.Substring(0, 1)) + 8];
                }
                else
                {
                    return DECENAS[int.Parse(num.Substring(0, 1)) + 8] + "y " + u;
                }
            }
            else
            {//numeros entre 11 y 19
                return DECENAS[n - 10];
            }
        }

        private String getCentenas(String num)
        {// 999 o 099
            if (int.Parse(num) > 99)
            {//es centena
                if (int.Parse(num) == 100)
                {//caso especial
                    return " cien ";
                }
                else
                {
                    return CENTENAS[int.Parse(num.Substring(0, 1))] + getDecenas(num.Substring(1));
                }
            }
            else
            {//por Ej. 099 
                //se quita el 0 antes de convertir a decenas
                return getDecenas(int.Parse(num) + "");
            }
        }

        private String getMiles(String numero)
        {// 999 999
            //obtiene las centenas
            String c = numero.Substring(numero.Length - 3);
            //obtiene los miles
            String m = numero.Substring(0, numero.Length - 3);
            String n = "";
            //se comprueba que miles tenga valor entero
            if (int.Parse(m) > 0)
            {
                n = getCentenas(m);
                return n + "mil " + getCentenas(c);
            }
            else
            {
                return "" + getCentenas(c);
            }

        }

        private String getMillones(String numero) 
        { //000 000 000        
            //se obtiene los miles
            String miles = numero.Substring(numero.Length - 6); 
            //se obtiene los millones
            String millon = numero.Substring(0, numero.Length - 6);
            String n = "";
            if (millon.Length > 1) 
            {
                n = getCentenas(millon) + "millones ";
            }
            else
            {
                n = getUnidades(millon) + "millon ";
            }
            return n + getMiles(miles);
        }

    }

}

 Esta clase, recibe  un numero de 0,00 a 999999999.00 en formato String, el separador decimal puede ser un punto (.) o una coma (,), ademas tiene un parametro booleano "mayusculas" el cual sea verdadero (true) o falso (false), retorna el resultado en mayusculas o minusculas, esta clase no acepta numeros negativos ni tampoco numero mayores o iguales a mil millones, aunque claro trate de escribir esta clase para que sea facilmente comprensible y asi pueda ser ampliado o modificado segun sus necesidades.

La forma de llamara a esta clase es:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace con_NumLetraC
{
    class Program
    {
        static void Main(string[] args)
        {
            NumLetra nl = new NumLetra();

            String numero = "57.60";            
            Console.WriteLine(nl.Convertir(numero,true));

            numero = "34557.70";
            Console.WriteLine(nl.Convertir(numero, false));

            numero = "4357,60";
            Console.WriteLine(nl.Convertir(numero, true));

            numero = "969.90";
            Console.WriteLine(nl.Convertir(numero, false));

            Console.ReadKey();
            
        }
    }
    
}

Y al ejecutar el proyecto tenemos:

17 comentarios:

yaya dijo...

muy buen ejemplo y está muy entendible, por los coemtarios que tiene, gracias por la aportacion

Anónimo dijo...

Gracias por el codigo, modifique algo para numeros y para formato moneda, muy buen codigo.

Anónimo dijo...

Muy mal!! En castellano los números no se escriben así, no se en que idioma hablas, es bastante ridículo el resultado del código.

Anónimo dijo...

muy bueno me sirvio

Anónimo dijo...

Esta muy bien aunque el ridiculo de arriba no sabe de esto

carlosjor dijo...

Están mal escritos "algunos" números en español, lo cual invalida el código por completo.

rixar dijo...

gracias por el codigo me sirvio mucho.

Anónimo dijo...

m

Anónimo dijo...

que programe ese estupido que solo critica,
muy bueno amigo yo lo modifique y me sirvio de mucho ;)

FE Y ALEGRIA 44 dijo...

oigan amigos como ago para que aparesca en el label me pueden ayudar

Rockdrigo dijo...

Muchas gracias por el aporte..muy bueno

Unknown dijo...

Hola
Tendrás este código en C++?
Seria de mucha ayuda.
Gracias y saludos

Ronald Miller Andrade dijo...

mil gracias amigo me sirvió bastante

Anónimo dijo...

mil gracias por el código me sirvió bastante

Anónimo dijo...

Mal validado el código. Amigo siento decirte que no tienes la mas mínima idea de lo que es POO.

Anónimo dijo...

tengo este error en ese ejercicio alguien me podria ayudar:

Unexpected token: namespace. (BCE0043) -
unexpected char: 'd'. (BCE0044) -

Unknown dijo...

Excelente Aportacion, Muchas Gracias Funciona para WM

Publicar un comentario

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | cna certification