Skip to content

Instantly share code, notes, and snippets.

@efrenfuentes
Created September 26, 2012 02:29
Show Gist options
  • 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()
@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