Skip to content

Instantly share code, notes, and snippets.

@efrenfuentes
Created September 26, 2012 02:29
Show Gist options
  • Star 24 You must be signed in to star a gist
  • Fork 17 You must be signed in to fork a gist
  • Save efrenfuentes/3785655 to your computer and use it in GitHub Desktop.
Save efrenfuentes/3785655 to your computer and use it in GitHub Desktop.
Numero a letras (Python)
#!/usr/bin/python
# -*- coding: utf-8 -*-
__author__ = 'efrenfuentes'
MONEDA_SINGULAR = 'bolivar'
MONEDA_PLURAL = 'bolivares'
CENTIMOS_SINGULAR = 'centimo'
CENTIMOS_PLURAL = 'centimos'
MAX_NUMERO = 999999999999
UNIDADES = (
'cero',
'uno',
'dos',
'tres',
'cuatro',
'cinco',
'seis',
'siete',
'ocho',
'nueve'
)
DECENAS = (
'diez',
'once',
'doce',
'trece',
'catorce',
'quince',
'dieciseis',
'diecisiete',
'dieciocho',
'diecinueve'
)
DIEZ_DIEZ = (
'cero',
'diez',
'veinte',
'treinta',
'cuarenta',
'cincuenta',
'sesenta',
'setenta',
'ochenta',
'noventa'
)
CIENTOS = (
'_',
'ciento',
'doscientos',
'trescientos',
'cuatroscientos',
'quinientos',
'seiscientos',
'setecientos',
'ochocientos',
'novecientos'
)
def numero_a_letras(numero):
numero_entero = int(numero)
if numero_entero > MAX_NUMERO:
raise OverflowError('Número demasiado alto')
if numero_entero < 0:
return 'menos %s' % numero_a_letras(abs(numero))
letras_decimal = ''
parte_decimal = int(round((abs(numero) - abs(numero_entero)) * 100))
if parte_decimal > 9:
letras_decimal = 'punto %s' % numero_a_letras(parte_decimal)
elif parte_decimal > 0:
letras_decimal = 'punto cero %s' % numero_a_letras(parte_decimal)
if (numero_entero <= 99):
resultado = leer_decenas(numero_entero)
elif (numero_entero <= 999):
resultado = leer_centenas(numero_entero)
elif (numero_entero <= 999999):
resultado = leer_miles(numero_entero)
elif (numero_entero <= 999999999):
resultado = leer_millones(numero_entero)
else:
resultado = leer_millardos(numero_entero)
resultado = resultado.replace('uno mil', 'un mil')
resultado = resultado.strip()
resultado = resultado.replace(' _ ', ' ')
resultado = resultado.replace(' ', ' ')
if parte_decimal > 0:
resultado = '%s %s' % (resultado, letras_decimal)
return resultado
def numero_a_moneda(numero):
numero_entero = int(numero)
parte_decimal = int(round((abs(numero) - abs(numero_entero)) * 100))
centimos = ''
if parte_decimal == 1:
centimos = CENTIMOS_SINGULAR
else:
centimos = CENTIMOS_PLURAL
moneda = ''
if numero_entero == 1:
moneda = MONEDA_SINGULAR
else:
moneda = MONEDA_PLURAL
letras = numero_a_letras(numero_entero)
letras = letras.replace('uno', 'un')
letras_decimal = 'con %s %s' % (numero_a_letras(parte_decimal).replace('uno', 'un'), centimos)
letras = '%s %s %s' % (letras, moneda, letras_decimal)
return letras
def leer_decenas(numero):
if numero < 10:
return UNIDADES[numero]
decena, unidad = divmod(numero, 10)
if numero <= 19:
resultado = DECENAS[unidad]
elif numero <= 29:
resultado = 'veinti%s' % UNIDADES[unidad]
else:
resultado = DIEZ_DIEZ[decena]
if unidad > 0:
resultado = '%s y %s' % (resultado, UNIDADES[unidad])
return resultado
def leer_centenas(numero):
centena, decena = divmod(numero, 100)
if numero == 0:
resultado = 'cien'
else:
resultado = CIENTOS[centena]
if decena > 0:
resultado = '%s %s' % (resultado, leer_decenas(decena))
return resultado
def leer_miles(numero):
millar, centena = divmod(numero, 1000)
resultado = ''
if (millar == 1):
resultado = ''
if (millar >= 2) and (millar <= 9):
resultado = UNIDADES[millar]
elif (millar >= 10) and (millar <= 99):
resultado = leer_decenas(millar)
elif (millar >= 100) and (millar <= 999):
resultado = leer_centenas(millar)
resultado = '%s mil' % resultado
if centena > 0:
resultado = '%s %s' % (resultado, leer_centenas(centena))
return resultado
def leer_millones(numero):
millon, millar = divmod(numero, 1000000)
resultado = ''
if (millon == 1):
resultado = ' un millon '
if (millon >= 2) and (millon <= 9):
resultado = UNIDADES[millon]
elif (millon >= 10) and (millon <= 99):
resultado = leer_decenas(millon)
elif (millon >= 100) and (millon <= 999):
resultado = leer_centenas(millon)
if millon > 1:
resultado = '%s millones' % resultado
if (millar > 0) and (millar <= 999):
resultado = '%s %s' % (resultado, leer_centenas(millar))
elif (millar >= 1000) and (millar <= 999999):
resultado = '%s %s' % (resultado, leer_miles(millar))
return resultado
def leer_millardos(numero):
millardo, millon = divmod(numero, 1000000)
return '%s millones %s' % (leer_miles(millardo), leer_millones(millon))
#!/usr/bin/python
# -*- coding: utf-8 -*-
__author__ = 'efrenfuentes'
import unittest
from numero_letras import numero_a_letras, numero_a_moneda
class TestNumeroLetras(unittest.TestCase):
def test_numero_demasiado_alto(self):
numero = 1000000000000
self.assertRaises(OverflowError, numero_a_letras, numero)
def test_unidades(self):
numero = 8
self.assertEqual(numero_a_letras(numero), 'ocho')
numero = 2
self.assertEqual(numero_a_letras(numero), 'dos')
numero = 0
self.assertEqual(numero_a_letras(numero), 'cero')
def test_decena_diez(self):
numero = 15
self.assertEqual(numero_a_letras(numero), 'quince')
numero = 17
self.assertEqual(numero_a_letras(numero), 'diecisiete')
numero = 19
self.assertEqual(numero_a_letras(numero), 'diecinueve')
def test_decena_veinte(self):
numero = 23
self.assertEqual(numero_a_letras(numero), 'veintitres')
numero = 26
self.assertEqual(numero_a_letras(numero), 'veintiseis')
numero = 21
self.assertEqual(numero_a_letras(numero), 'veintiuno')
def test_menores_cien(self):
numero = 32
self.assertEqual(numero_a_letras(numero), 'treinta y dos')
numero = 73
self.assertEqual(numero_a_letras(numero), 'setenta y tres')
numero = 89
self.assertEqual(numero_a_letras(numero), 'ochenta y nueve')
def test_centenas(self):
numero = 167
self.assertEqual(numero_a_letras(numero), 'ciento sesenta y siete')
numero = 735
self.assertEqual(numero_a_letras(numero), 'setecientos treinta y cinco')
numero = 899
self.assertEqual(numero_a_letras(numero), 'ochocientos noventa y nueve')
def test_miles(self):
numero = 1973
self.assertEqual(numero_a_letras(numero), 'mil novecientos setenta y tres')
numero = 5230
self.assertEqual(numero_a_letras(numero), 'cinco mil doscientos treinta')
numero = 41378
self.assertEqual(numero_a_letras(numero), 'cuarenta y un mil trescientos setenta y ocho')
numero = 197356
self.assertEqual(numero_a_letras(numero), 'ciento noventa y siete mil trescientos cincuenta y seis')
numero = 2004
self.assertEqual(numero_a_letras(numero), 'dos mil cuatro')
def test_millones(self):
numero = 11852739
self.assertEqual(numero_a_letras(numero), 'once millones ochocientos cincuenta y dos mil setecientos treinta y nueve')
numero = 2000000
self.assertEqual(numero_a_letras(numero), 'dos millones')
def test_millardos(self):
numero = 1212673201
self.assertEqual(numero_a_letras(numero), 'mil doscientos doce millones seiscientos setenta y tres mil doscientos uno')
numero = 56547567945
self.assertEqual(numero_a_letras(numero), 'cincuenta y seis mil quinientos cuarenta y siete millones quinientos sesenta y siete mil novecientos cuarenta y cinco')
def test_decimales(self):
numero = 1.87
self.assertEqual(numero_a_letras(numero), 'uno punto ochenta y siete')
numero = 1.50
self.assertEqual(numero_a_letras(numero), 'uno punto cincuenta')
numero = 1.04
self.assertEqual(numero_a_letras(numero), 'uno punto cero cuatro')
numero = 1.00
self.assertEqual(numero_a_letras(numero), 'uno')
def test_negativos(self):
numero = -4.5
self.assertEqual(numero_a_letras(numero), 'menos cuatro punto cincuenta')
def test_moneda(self):
numero = 1212673201
self.assertEqual(numero_a_moneda(numero), 'mil doscientos doce millones seiscientos setenta y tres mil doscientos un bolivares con cero centimos')
numero = 56547567945.5
self.assertEqual(numero_a_moneda(numero), 'cincuenta y seis mil quinientos cuarenta y siete millones quinientos sesenta y siete mil novecientos cuarenta y cinco bolivares con cincuenta centimos')
numero = 1.01
self.assertEqual(numero_a_moneda(numero), 'un bolivar con un centimo')
if __name__ == '__main__':
unittest.main()
@sdelquin
Copy link

sdelquin commented Dec 9, 2016

Hay un error

20 -> veinticero

Cambiar línea 122 por:
elif 21 <= numero <= 29:

Muchas gracias por la librería!

@jesus01x
Copy link

jesus01x commented Nov 13, 2017

Imagino que quisiste decir que modificara esta linea en especifico -->elif numero <= 29: por lo que comentaste es decir elif 21 <= numero <= 29: si asi en este codigo fuente esa linea es la 121 , no 122.

@robertowest
Copy link

En la línea 132 también tienes un error:
if numero == 0:
debería ser:
if decena == 0:

Saludos.

@Gztabo21
Copy link

Gztabo21 commented Sep 5, 2019

se ve interesante la probare

@FabrizioMore
Copy link

FabrizioMore commented Feb 20, 2020

Hola! Muchas gracias por la librería, me ayudó mucho en un proyecto personal <3
Quería señalar que en la función leer_centenas (línea 130) debí reemplazar el código por:
Sin título
debido a que al ingresar un número distinto de 100.000 pero cuyo modulo fuera 0 (ej: 300.000), como respuesta recibía 'cien mil'.

@Gztabo21
Copy link

Gztabo21 commented Feb 20, 2020 via email

@Septiembre19
Copy link

Muchas gracias y de igual forma, gracias a las demas personas con las correciones.

@lfranc2
Copy link

lfranc2 commented Jun 6, 2020

Hay un error. 100 -> Ciento.

@VictorVegaPintaComex
Copy link

Hay error con los siguientes valores 100,200,300,400,500,600,700,800,900

@Pollux3
Copy link

Pollux3 commented Nov 24, 2020

En la línea 132 también tienes un error:
if numero == 0:
debería ser:
if decena == 0:

Saludos.

en la 132 me sale con, ya lo he probado.
'if centena ==0:'
#Ya que siempre la decenas para los números que terminan en 00 se quedarán ahi.
Genial el aporte efrenfuentes.

@evallardy
Copy link

Al resultado falta agregarle algunos reeplazos para texto con moneda

resultado = resultado.replace('cientos uno', 'cientos un')
resultado = resultado.replace('ciento uno', 'ciento un')
resultado = resultado.replace('quinientos uno', 'quinientos un')

No podemos decir "quinietos uno pesos" en mi caso México o "quinietos uno bolivares" porque lo real es "quinietos un pesos" o "quinietos un bolivares" igual pasa con todos los cientos, doscientos, trecientos, etc.

Saludos y muchisimas gracias por la aportación

@jcesar020
Copy link

jcesar020 commented Mar 31, 2022

Gracia por el codigo veo que sean corregido las observaciones de los demas usuaros, yo solo cree un metodo para colocar los centimos en formato de fraccion ya que asi los utilizo mas

def numero_a_monedas(numero):
    numero_entero = int(numero)
    parte_decimal = int(round((abs(numero) - abs(numero_entero)) * 100))
    
    letras = numero_a_letras(numero_entero)
    letras_decimal = f'{parte_decimal:02n}/100 { MONEDA_PLURAL}'
    letras = '%s %s' % (letras, letras_decimal)
    return letras

por ejemplo
print(numero_a_monedas(300000.23).upper())
tenemos:
TRESCIENTOS MIL 23/100 DOLARES

@wzorroman
Copy link

wzorroman commented Jun 10, 2022

Yo hice un update a este codigo basado en python3 y espero les ayude.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment