Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

Número por extenso com unidades de medida

By: aricaldeira on Mar 7th, 2011  |  syntax: Python  |  size: 21.21 KB  |  views: 600  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. '''
  4. Números por extenso, cardinais, ordinais e cardinais com unidades de medida
  5.  
  6. Compatível com as versões 2 e 3 do Python
  7. '''
  8.  
  9. from __future__ import division, print_function, unicode_literals
  10.  
  11. from decimal import Decimal as D
  12.  
  13.  
  14. PLURAL = 1
  15. SINGULAR = 0
  16.  
  17. CARDINAL = 1
  18. ORDINAL = 0
  19.  
  20. MASCULINO = 1
  21. FEMININO = 0
  22.  
  23.  
  24. #
  25. # Número cardinais
  26. #
  27. CARDINAL_0 = 'zero'
  28. CARDINAL_1 = 'um'
  29. CARDINAL_2 = 'dois'
  30. CARDINAL_3 = 'três'
  31. CARDINAL_4 = 'quatro'
  32. CARDINAL_5 = 'cinco'
  33. CARDINAL_6 = 'seis'
  34. CARDINAL_7 = 'sete'
  35. CARDINAL_8 = 'oito'
  36. CARDINAL_9 = 'nove'
  37.  
  38. CARDINAL_10 = 'dez'
  39. CARDINAL_11 = 'onze'
  40. CARDINAL_12 = 'doze'
  41. CARDINAL_13 = 'treze'
  42. CARDINAL_14 = 'catorze'
  43. CARDINAL_15 = 'quinze'
  44. CARDINAL_16 = 'dezesseis'
  45. CARDINAL_17 = 'dezessete'
  46. CARDINAL_18 = 'dezoito'
  47. CARDINAL_19 = 'dezenove'
  48. CARDINAL_20 = 'vinte'
  49. CARDINAL_30 = 'trinta'
  50. CARDINAL_40 = 'quarenta'
  51. CARDINAL_50 = 'cinquenta'
  52. CARDINAL_60 = 'sessenta'
  53. CARDINAL_70 = 'setenta'
  54. CARDINAL_80 = 'oitenta'
  55. CARDINAL_90 = 'noventa'
  56.  
  57. CARDINAL_100_ISOLADO = 'cem'
  58.  
  59. CARDINAL_100 = 'cento'
  60. CARDINAL_200 = 'duzentos'
  61. CARDINAL_300 = 'trezentos'
  62. CARDINAL_400 = 'quatrocentos'
  63. CARDINAL_500 = 'quinhentos'
  64. CARDINAL_600 = 'seiscentos'
  65. CARDINAL_700 = 'setecentos'
  66. CARDINAL_800 = 'oitocentos'
  67. CARDINAL_900 = 'novecentos'
  68.  
  69. CARDINAL_1_FEMININO = 'uma'
  70. CARDINAL_2_FEMININO = 'duas'
  71.  
  72. CARDINAL_200_FEMININO = 'duzentas'
  73. CARDINAL_300_FEMININO = 'trezentas'
  74. CARDINAL_400_FEMININO = 'quatrocentas'
  75. CARDINAL_500_FEMININO = 'quinhentas'
  76. CARDINAL_600_FEMININO = 'seiscentas'
  77. CARDINAL_700_FEMININO = 'setecentas'
  78. CARDINAL_800_FEMININO = 'oitocentas'
  79. CARDINAL_900_FEMININO = 'novecentas'
  80.  
  81. CARDINAL_MASCULINO = {
  82.       0: CARDINAL_0,
  83.       1: CARDINAL_1,
  84.       2: CARDINAL_2,
  85.       3: CARDINAL_3,
  86.       4: CARDINAL_4,
  87.       5: CARDINAL_5,
  88.       6: CARDINAL_6,
  89.       7: CARDINAL_7,
  90.       8: CARDINAL_8,
  91.       9: CARDINAL_9,
  92.      10: CARDINAL_10,
  93.      11: CARDINAL_11,
  94.      12: CARDINAL_12,
  95.      13: CARDINAL_13,
  96.      14: CARDINAL_14,
  97.      15: CARDINAL_15,
  98.      16: CARDINAL_16,
  99.      17: CARDINAL_17,
  100.      18: CARDINAL_18,
  101.      19: CARDINAL_19,
  102.      20: CARDINAL_20,
  103.      30: CARDINAL_30,
  104.      40: CARDINAL_40,
  105.      50: CARDINAL_50,
  106.      60: CARDINAL_60,
  107.      70: CARDINAL_70,
  108.      80: CARDINAL_80,
  109.      90: CARDINAL_90,
  110.     100: CARDINAL_100,
  111.     200: CARDINAL_200,
  112.     300: CARDINAL_300,
  113.     400: CARDINAL_400,
  114.     500: CARDINAL_500,
  115.     600: CARDINAL_600,
  116.     700: CARDINAL_700,
  117.     800: CARDINAL_800,
  118.     900: CARDINAL_900,
  119.     }
  120.  
  121. CARDINAL_FEMININO = CARDINAL_MASCULINO.copy()
  122.  
  123. CARDINAL_FEMININO.update({
  124.     1: CARDINAL_1_FEMININO,
  125.     2: CARDINAL_2_FEMININO,
  126.     200: CARDINAL_200_FEMININO,
  127.     300: CARDINAL_300_FEMININO,
  128.     400: CARDINAL_400_FEMININO,
  129.     500: CARDINAL_500_FEMININO,
  130.     600: CARDINAL_600_FEMININO,
  131.     700: CARDINAL_700_FEMININO,
  132.     800: CARDINAL_800_FEMININO,
  133.     900: CARDINAL_900_FEMININO,
  134.     })
  135.    
  136. NOME_CARDINAL_POTENCIA = {
  137.     10**3: ('mil', 'mil'),
  138.     10**6: ('milhão', 'milhões'),
  139.     10**9: ('bilhão', 'bilhões'),
  140.     10**12: ('trilhão', 'trilhões'),
  141.     10**15: ('quatrilhão', 'quatrilhões'),
  142.     10**18: ('quintilhão', 'quintilhões'),
  143.     10**21: ('sextilhão', 'sextilhões'),
  144.     10**24: ('setilhão', 'setilhões'),
  145.     10**27: ('octilhão', 'octilhões'),
  146.     10**30: ('nonilhão', 'nonilhões'),
  147.     10**33: ('decilhão', 'decilhões'),
  148.     10**36: ('undecilhão', 'undecilhões'),
  149.     10**39: ('dodecilhão', 'duodecilhões'),
  150.     10**42: ('tredecilhão', 'tredecilhões'),
  151.     10**45: ('quatuordecilhão', 'quatuordecilhões'),
  152.     10**48: ('quindecilhão', 'quindecilhões'),
  153.     10**51: ('sesdecilhão', 'sesdecilhões'),
  154.     10**54: ('septendecilhão', 'septendecilhões'),
  155.     10**57: ('octodecilhão', 'octodecilhões'),
  156.     10**60: ('nonidecilhão', 'nonidecilhões'),
  157.     }
  158.  
  159. #
  160. # Número ordinais
  161. #
  162. ORDINAL_1 = 'primeiro'
  163. ORDINAL_2 = 'segundo'
  164. ORDINAL_3 = 'terceiro'
  165. ORDINAL_4 = 'quarto'
  166. ORDINAL_5 = 'quinto'
  167. ORDINAL_6 = 'sexto'
  168. ORDINAL_7 = 'sétimo'
  169. ORDINAL_8 = 'oitavo'
  170. ORDINAL_9 = 'nono'
  171.  
  172. ORDINAL_10 = 'décimo'
  173. ORDINAL_11 = ORDINAL_10 + ' ' + ORDINAL_1
  174. ORDINAL_12 = ORDINAL_10 + ' ' + ORDINAL_2
  175. ORDINAL_13 = ORDINAL_10 + ' ' + ORDINAL_3
  176. ORDINAL_14 = ORDINAL_10 + ' ' + ORDINAL_4
  177. ORDINAL_15 = ORDINAL_10 + ' ' + ORDINAL_5
  178. ORDINAL_16 = ORDINAL_10 + ' ' + ORDINAL_6
  179. ORDINAL_17 = ORDINAL_10 + ' ' + ORDINAL_7
  180. ORDINAL_18 = ORDINAL_10 + ' ' + ORDINAL_8
  181. ORDINAL_19 = ORDINAL_10 + ' ' + ORDINAL_9
  182. ORDINAL_20 = 'vigésimo'
  183. ORDINAL_30 = 'trigésimo'
  184. ORDINAL_40 = 'quadragésimo'
  185. ORDINAL_50 = 'quinquagésimo'
  186. ORDINAL_60 = 'sexagésimo'
  187. ORDINAL_70 = 'septuagésimo'
  188. ORDINAL_80 = 'octogésimo'
  189. ORDINAL_90 = 'nonagésimo'
  190.  
  191. ORDINAL_100 = 'centésimo'
  192. ORDINAL_200 = 'ducentésimo'
  193. ORDINAL_300 = 'tricentésimo'
  194. ORDINAL_400 = 'quadringentésimo'
  195. ORDINAL_500 = 'quingentésimo'
  196. ORDINAL_600 = 'seiscentésimo'
  197. ORDINAL_700 = 'septigentésimo'
  198. ORDINAL_800 = 'octingentésimo'
  199. ORDINAL_900 = 'noningentésimo'
  200.  
  201. ORDINAL_1_FEMININO = 'primeira'
  202. ORDINAL_2_FEMININO = 'segunda'
  203. ORDINAL_3_FEMININO = 'terceira'
  204. ORDINAL_4_FEMININO = 'quarta'
  205. ORDINAL_5_FEMININO = 'quinta'
  206. ORDINAL_6_FEMININO = 'sexta'
  207. ORDINAL_7_FEMININO = 'sétima'
  208. ORDINAL_8_FEMININO = 'oitava'
  209. ORDINAL_9_FEMININO = 'nona'
  210.  
  211. ORDINAL_10_FEMININO = 'décima'
  212. ORDINAL_11_FEMININO = ORDINAL_10_FEMININO + ' ' + ORDINAL_1_FEMININO
  213. ORDINAL_12_FEMININO = ORDINAL_10_FEMININO + ' ' + ORDINAL_2_FEMININO
  214. ORDINAL_13_FEMININO = ORDINAL_10_FEMININO + ' ' + ORDINAL_3_FEMININO
  215. ORDINAL_14_FEMININO = ORDINAL_10_FEMININO + ' ' + ORDINAL_4_FEMININO
  216. ORDINAL_15_FEMININO = ORDINAL_10_FEMININO + ' ' + ORDINAL_5_FEMININO
  217. ORDINAL_16_FEMININO = ORDINAL_10_FEMININO + ' ' + ORDINAL_6_FEMININO
  218. ORDINAL_17_FEMININO = ORDINAL_10_FEMININO + ' ' + ORDINAL_7_FEMININO
  219. ORDINAL_18_FEMININO = ORDINAL_10_FEMININO + ' ' + ORDINAL_8_FEMININO
  220. ORDINAL_19_FEMININO = ORDINAL_10_FEMININO + ' ' + ORDINAL_9_FEMININO
  221. ORDINAL_20_FEMININO = 'vigésima'
  222. ORDINAL_30_FEMININO = 'trigésima'
  223. ORDINAL_40_FEMININO = 'quadragésima'
  224. ORDINAL_50_FEMININO = 'quinquagésima'
  225. ORDINAL_60_FEMININO = 'sexagésima'
  226. ORDINAL_70_FEMININO = 'septuagésima'
  227. ORDINAL_80_FEMININO = 'octogésima'
  228. ORDINAL_90_FEMININO = 'nonagésima'
  229.  
  230. ORDINAL_100_FEMININO = 'centésima'
  231. ORDINAL_200_FEMININO = 'ducentésima'
  232. ORDINAL_300_FEMININO = 'tricentésima'
  233. ORDINAL_400_FEMININO = 'quadringentésima'
  234. ORDINAL_500_FEMININO = 'quingentésima'
  235. ORDINAL_600_FEMININO = 'seiscentésima'
  236. ORDINAL_700_FEMININO = 'septigentésima'
  237. ORDINAL_800_FEMININO = 'octingentésima'
  238. ORDINAL_900_FEMININO = 'noningentésima'
  239.  
  240. ORDINAL_MASCULINO = {
  241.       0: CARDINAL_0,
  242.       1: ORDINAL_1,
  243.       2: ORDINAL_2,
  244.       3: ORDINAL_3,
  245.       4: ORDINAL_4,
  246.       5: ORDINAL_5,
  247.       6: ORDINAL_6,
  248.       7: ORDINAL_7,
  249.       8: ORDINAL_8,
  250.       9: ORDINAL_9,
  251.      10: ORDINAL_10,
  252.      11: ORDINAL_11,
  253.      12: ORDINAL_12,
  254.      13: ORDINAL_13,
  255.      14: ORDINAL_14,
  256.      15: ORDINAL_15,
  257.      16: ORDINAL_16,
  258.      17: ORDINAL_17,
  259.      18: ORDINAL_18,
  260.      19: ORDINAL_19,
  261.      20: ORDINAL_20,
  262.      30: ORDINAL_30,
  263.      40: ORDINAL_40,
  264.      50: ORDINAL_50,
  265.      60: ORDINAL_60,
  266.      70: ORDINAL_70,
  267.      80: ORDINAL_80,
  268.      90: ORDINAL_90,
  269.     100: ORDINAL_100,
  270.     200: ORDINAL_200,
  271.     300: ORDINAL_300,
  272.     400: ORDINAL_400,
  273.     500: ORDINAL_500,
  274.     600: ORDINAL_600,
  275.     700: ORDINAL_700,
  276.     800: ORDINAL_800,
  277.     900: ORDINAL_900,
  278.     }
  279.    
  280. ORDINAL_FEMININO = {
  281.       0: CARDINAL_0,
  282.       1: ORDINAL_1_FEMININO,
  283.       2: ORDINAL_2_FEMININO,
  284.       3: ORDINAL_3_FEMININO,
  285.       4: ORDINAL_4_FEMININO,
  286.       5: ORDINAL_5_FEMININO,
  287.       6: ORDINAL_6_FEMININO,
  288.       7: ORDINAL_7_FEMININO,
  289.       8: ORDINAL_8_FEMININO,
  290.       9: ORDINAL_9_FEMININO,
  291.      10: ORDINAL_10_FEMININO,
  292.      11: ORDINAL_11_FEMININO,
  293.      12: ORDINAL_12_FEMININO,
  294.      13: ORDINAL_13_FEMININO,
  295.      14: ORDINAL_14_FEMININO,
  296.      15: ORDINAL_15_FEMININO,
  297.      16: ORDINAL_16_FEMININO,
  298.      17: ORDINAL_17_FEMININO,
  299.      18: ORDINAL_18_FEMININO,
  300.      19: ORDINAL_19_FEMININO,
  301.      20: ORDINAL_20_FEMININO,
  302.      30: ORDINAL_30_FEMININO,
  303.      40: ORDINAL_40_FEMININO,
  304.      50: ORDINAL_50_FEMININO,
  305.      60: ORDINAL_60_FEMININO,
  306.      70: ORDINAL_70_FEMININO,
  307.      80: ORDINAL_80_FEMININO,
  308.      90: ORDINAL_90_FEMININO,
  309.     100: ORDINAL_100_FEMININO,
  310.     200: ORDINAL_200_FEMININO,
  311.     300: ORDINAL_300_FEMININO,
  312.     400: ORDINAL_400_FEMININO,
  313.     500: ORDINAL_500_FEMININO,
  314.     600: ORDINAL_600_FEMININO,
  315.     700: ORDINAL_700_FEMININO,
  316.     800: ORDINAL_800_FEMININO,
  317.     900: ORDINAL_900_FEMININO,
  318.     }
  319.    
  320. NOME_ORDINAL_POTENCIA_MASCULINO = {
  321.     10**3: ('milésimo', 'milésimo'),
  322.     10**6: ('milionésimo', 'milionésimo'),
  323.     10**9: ('bilionésimo', 'bilionésimo'),
  324.     10**12: ('trilionésimo', 'trilionésimo'),
  325.     10**15: ('quatrilionésimo', 'quatrilionésimo'),
  326.     10**18: ('quintilionésimo', 'quitilionésimo'),
  327.     10**21: ('sextilionésimo', 'sextilionésimo'),
  328.     10**24: ('setilionésimo', 'setilionésimo'),
  329.     10**27: ('octilionésimo', 'octilionésimo'),
  330.     10**30: ('nonilionésimo', 'nonilionésimo'),
  331.     10**33: ('decilionésimo', 'decilionésimo'),
  332.     10**36: ('undecilionésimo', 'undecilionésimo'),
  333.     10**39: ('dodecilionésimo', 'duodecilionésimo'),
  334.     10**42: ('tredecilionésimo', 'tredecilionésimo'),
  335.     10**45: ('quatuordecilionésimo', 'quatuordecilionésimo'),
  336.     10**48: ('quindecilionésimo', 'quindecilionésimo'),
  337.     10**51: ('sesdecilionésimo', 'sesdecilionésimo'),
  338.     10**54: ('septendecilionésimo', 'septendecilionésimo'),
  339.     10**57: ('octodecilionésimo', 'octodecilionésimo'),
  340.     10**60: ('nonidecilionésimo', 'nonidecilionésimo'),
  341.     }
  342.  
  343. NOME_ORDINAL_POTENCIA_FEMININO = {
  344.     10**3: ('milésima', 'milésima'),
  345.     10**6: ('milionésima', 'milionésima'),
  346.     10**9: ('bilionésima', 'bilionésima'),
  347.     10**12: ('trilionésima', 'trilionésima'),
  348.     10**15: ('quatrilionésima', 'quatrilionésima'),
  349.     10**18: ('quintilionésima', 'quitilionésima'),
  350.     10**21: ('sextilionésima', 'sextilionésima'),
  351.     10**24: ('setilionésima', 'setilionésima'),
  352.     10**27: ('octilionésima', 'octilionésima'),
  353.     10**30: ('nonilionésima', 'nonilionésima'),
  354.     10**33: ('decilionésima', 'decilionésima'),
  355.     10**36: ('undecilionésima', 'undecilionésima'),
  356.     10**39: ('dodecilionésima', 'duodecilionésima'),
  357.     10**42: ('tredecilionésima', 'tredecilionésima'),
  358.     10**45: ('quatuordecilionésima', 'quatuordecilionésima'),
  359.     10**48: ('quindecilionésima', 'quindecilionésima'),
  360.     10**51: ('sesdecilionésima', 'sesdecilionésima'),
  361.     10**54: ('septendecilionésima', 'septendecilionésima'),
  362.     10**57: ('octodecilionésima', 'octodecilionésima'),
  363.     10**60: ('nonidecilionésima', 'nonidecilionésima'),
  364.     }
  365.    
  366. EXTENSO = {
  367.     CARDINAL: {
  368.         MASCULINO: CARDINAL_MASCULINO,
  369.         FEMININO: CARDINAL_FEMININO,
  370.         },
  371.     ORDINAL: {
  372.         MASCULINO: ORDINAL_MASCULINO,
  373.         FEMININO: ORDINAL_FEMININO,
  374.         }
  375.     }
  376.    
  377. NOME_POTENCIA = {
  378.     CARDINAL: {
  379.         MASCULINO: NOME_CARDINAL_POTENCIA,
  380.         FEMININO: NOME_CARDINAL_POTENCIA,
  381.         },
  382.     ORDINAL: {
  383.         MASCULINO: NOME_ORDINAL_POTENCIA_MASCULINO,
  384.         FEMININO: NOME_ORDINAL_POTENCIA_FEMININO,
  385.         }
  386.     }
  387.    
  388. VALOR_MAXIMO = max(NOME_CARDINAL_POTENCIA)
  389.  
  390.  
  391. class NumeroPorExtenso(object):
  392.     def __init__(self, numero=0, unidade=('real', 'reais'), genero_unidade_masculino=True,
  393.         precisao_decimal=2, unidade_decimal=('centavo', 'centavos'),
  394.         genero_unidade_decimal_masculino=True, mascara_negativo=('menos %s', 'menos %s'),
  395.         fator_relacao_decimal=1):
  396.         self.numero = numero
  397.         self.unidade = unidade
  398.         self.genero_unidade_masculino = genero_unidade_masculino
  399.         self.precisao_decimal = precisao_decimal
  400.         self.fator_relacao_decimal = fator_relacao_decimal
  401.         self.unidade_decimal = unidade_decimal
  402.         self.genero_unidade_decimal_masculino = genero_unidade_decimal_masculino
  403.         self.mascara_negativo = mascara_negativo
  404.        
  405.     def get_numero(self):
  406.         return self._numero
  407.        
  408.     def set_numero(self, valor):
  409.         if D(str(valor)) > VALOR_MAXIMO:
  410.             raise OverflowError('valor maior do que o máximo permitido: %s' % VALOR_MAXIMO)
  411.  
  412.         self._numero = D(str(valor))
  413.        
  414.     numero = property(get_numero, set_numero)
  415.  
  416.     def get_fator_relacao_decimal(self):
  417.         return self._fator_relacao_decimal
  418.        
  419.     def set_fator_relacao_decimal(self, valor):
  420.         self._fator_relacao_decimal = D(str(valor))
  421.        
  422.     fator_relacao_decimal = property(get_fator_relacao_decimal, set_fator_relacao_decimal)
  423.  
  424.     def _centena_dezena_unidade(self, numero, tipo=CARDINAL, genero=MASCULINO):
  425.         assert 0 <= numero < 1000
  426.        
  427.         #
  428.         # Tratamento especial do número 100
  429.         #
  430.         if (numero == 100) and (tipo == CARDINAL):
  431.             return CARDINAL_100_ISOLADO
  432.            
  433.         if numero in EXTENSO[tipo][genero]:
  434.             return EXTENSO[tipo][genero][numero]
  435.  
  436.         potencia_10 = int(10 ** int(D(numero).log10()))
  437.         cabeca = int(numero / potencia_10) * potencia_10
  438.         corpo = int(numero % potencia_10)
  439.        
  440.         if tipo == CARDINAL:
  441.             return EXTENSO[tipo][genero][cabeca] + ' e ' + self._centena_dezena_unidade(corpo, tipo, genero)
  442.         else:
  443.             return EXTENSO[tipo][genero][cabeca] + ' ' + self._centena_dezena_unidade(corpo, tipo, genero)
  444.    
  445.     def _potencia(self, numero, tipo=CARDINAL, genero=MASCULINO):
  446.         potencia_10 = 1000 ** int((len(str(int(numero))) - 1) / 3)
  447.        
  448.         if potencia_10 <= 100:
  449.             return self._centena_dezena_unidade(numero, tipo, genero)
  450.        
  451.         este_grupo = int(numero / potencia_10)
  452.         proximo_grupo = numero - (este_grupo * potencia_10)
  453.  
  454.         #
  455.         # Tratamento especial para o número 1.000:
  456.         #     cardinais:
  457.         #         um mil -> mil
  458.         #         uma mil -> mil
  459.         #
  460.         if (tipo == CARDINAL) and (potencia_10 == 1000) and (este_grupo == 1):
  461.             texto = ''
  462.            
  463.         #    
  464.         # Tratamento especial para os números 1.000, 1.000.000 etc.
  465.         #     ordinais:
  466.         #         primeiro milésimo -> milésimo
  467.         #         primeira milésima -> milésima
  468.         #         primeiro milionésimo -> milionésimo
  469.         #         primeira milionésima -> milionésima
  470.         #
  471.         elif (tipo == ORDINAL) and (potencia_10 >= 1000) and (este_grupo == 1):
  472.             texto = ''
  473.            
  474.         else:
  475.             #
  476.             # Nos número cardinais, o gênero feminino só é usado até os milhares
  477.             #
  478.             if (tipo == CARDINAL) and (potencia_10 > 1000):
  479.                 texto = self._centena_dezena_unidade(este_grupo, tipo, MASCULINO)
  480.             else:
  481.                 texto = self._centena_dezena_unidade(este_grupo, tipo, genero)
  482.            
  483.         if len(texto):
  484.             texto += ' '
  485.            
  486.         texto += NOME_POTENCIA[tipo][genero][potencia_10][este_grupo > 1]
  487.  
  488.         #
  489.         # Conexão entre os grupos
  490.         #
  491.         if proximo_grupo > 0:
  492.             if (tipo == CARDINAL) and ((proximo_grupo <= 100) or (proximo_grupo in EXTENSO[tipo][genero])):
  493.                 texto += ' e '
  494.             elif (tipo == CARDINAL) and (potencia_10 != 1000):
  495.                 texto += ', '
  496.             else:
  497.                 texto += ' '
  498.  
  499.             texto += self._potencia(proximo_grupo, tipo, genero)
  500.                
  501.         return texto
  502.        
  503.     def get_extenso_cardinal(self):
  504.         '''
  505.         Número cardinal sem unidade, somente a parte inteira, somente números positivos
  506.         '''
  507.         return self._potencia(abs(int(self.numero)), tipo=CARDINAL, genero=MASCULINO)
  508.  
  509.     extenso_cardinal = property(get_extenso_cardinal)
  510.    
  511.     def get_extenso_ordinal(self):
  512.         '''
  513.         Número ordinal sem unidade, considerando o gênero da unidade
  514.         '''
  515.         if self._numero == 0:
  516.             return ''
  517.            
  518.         return self._potencia(abs(int(self.numero)), tipo=ORDINAL, genero=self.genero_unidade_masculino)
  519.  
  520.     extenso_ordinal = property(get_extenso_ordinal)
  521.    
  522.     def get_extenso_unidade(self):
  523.         '''
  524.         Número ordinal com unidade, parte inteira e decimal, com tratamento de negativos
  525.         '''
  526.         #
  527.         # Tratamento do zero, cuja unidade é sempre no plural: zero reais, zero graus etc.
  528.         #
  529.         if self.numero == 0:
  530.             texto = CARDINAL_0
  531.            
  532.             if len(self.unidade[PLURAL]):
  533.                 texto += ' ' + self.unidade[PLURAL]
  534.                
  535.             return texto
  536.            
  537.         #
  538.         # Separação da parte decimal com a precisão desejada
  539.         #
  540.         negativo = self.numero < 0
  541.         numero = abs(self.numero)
  542.         inteiro = int(numero)
  543.         decimal = int(((numero - inteiro) * self.fator_relacao_decimal) * (10 ** self.precisao_decimal))
  544.        
  545.         #
  546.         # Extenso da parte inteira
  547.         #
  548.         if inteiro > 0:
  549.             texto_inteiro = self._potencia(inteiro, genero=self.genero_unidade_masculino)
  550.        
  551.             if (inteiro == 1) and (len(self.unidade[SINGULAR])):
  552.                 texto_inteiro += ' ' + self.unidade[SINGULAR]
  553.             elif len(self.unidade[PLURAL]):
  554.                 texto_inteiro += ' ' + self.unidade[PLURAL]
  555.  
  556.         #
  557.         # Extenso da parte decimal
  558.         #
  559.         if decimal > 0:
  560.             texto_decimal = self._potencia(decimal, genero=self.genero_unidade_decimal_masculino)
  561.  
  562.             if (decimal == 1) and (len(self.unidade_decimal[SINGULAR])):
  563.                 texto_decimal += ' ' + self.unidade_decimal[SINGULAR]
  564.             elif len(self.unidade_decimal[PLURAL]):
  565.                 texto_decimal += ' ' + self.unidade_decimal[PLURAL]
  566.                
  567.         if (inteiro > 0) and (decimal > 0):
  568.             texto = texto_inteiro + ' e ' + texto_decimal
  569.         elif inteiro > 0:
  570.             texto = texto_inteiro
  571.         else:
  572.             texto = texto_decimal
  573.  
  574.         if negativo:
  575.             if ((inteiro > 1) or (decimal > 1)):
  576.                 texto = self.mascara_negativo[PLURAL] % texto
  577.             else:
  578.                 texto = self.mascara_negativo[SINGULAR] % texto
  579.        
  580.         return texto
  581.            
  582.     extenso_unidade = property(get_extenso_unidade)        
  583.    
  584.  
  585. if __name__ == '__main__':
  586.     import sys
  587.    
  588.     e = NumeroPorExtenso(sys.argv[1])
  589.    
  590.     print('Numeral cardinal simples:', e.extenso_cardinal)
  591.     print('Numeral ordinal simples:', e.extenso_ordinal)
  592.     print('Valor monetário em R$:', e.extenso_unidade)
  593.    
  594.     #
  595.     # Unidades sempre definidas na forma
  596.     # (unidade_no_singular, unidade_no_plural)
  597.     #
  598.     e.unidade = ('quilograma', 'quilogramas')
  599.     #
  600.     # 3 casas decimais de precisão, pois 1 quilograma são 1000 gramas
  601.     #
  602.     e.precisao_decimal = 3
  603.     e.unidade_decimal = ('grama', 'gramas')
  604.     print('Valor em quilogramas e gramas (com 3 casas decimais de precisão):', e.extenso_unidade)
  605.  
  606.     e.unidade = ('tonelada', 'toneladas')
  607.     e.genero_unidade_masculino = False
  608.     #
  609.     # 3 casas decimais de precisão, pois 1 tonelada são 1000 quilogramas
  610.     #
  611.     e.precisao_decimal = 3
  612.     e.unidade_decimal = ('quilograma', 'quilogramas')
  613.     e.genero_unidade_decimal_masculino = True
  614.     print('Valor em toneladas (feminino) e quilogramas (masculino, com 3 casa decimais de precisão):', e.extenso_unidade)
  615.  
  616.     e.unidade = ('dia', 'dias')
  617.     e.precisao_decimal = 1
  618.     e.unidade_decimal = ('hora', 'horas')
  619.     e.genero_unidade_decimal_masculino = False
  620.     #
  621.     # Se a relação entre a unidade e a unidade decimal não for, bem, decimal...
  622.     # No caso, se a precisão é 1, 0,1 dias são quantas horas?
  623.     #
  624.     e.fator_relacao_decimal = D('2.4')
  625.     print('Valor em dias e horas (com 1 casa decimal de precisão):', e.extenso_unidade)
  626.  
  627.     e.unidade = ('pé', 'pés')
  628.     e.precisao_decimal = 2
  629.     e.unidade_decimal = ('polegada', 'polegadas')
  630.     #
  631.     # Se a relação entre a unidade e a unidade decimal não for, bem, decimal...
  632.     # No caso, se a precisão é 2, 0,01 pés são quantas polegadas?
  633.     # Melhor informar em Decimal para evitar problemas de arredondamento
  634.     #
  635.     e.fator_relacao_decimal = D('0.12')
  636.     print('Valor em pés e polegadas (com 2 casas decimais de precisão):', e.extenso_unidade)
  637.  
  638.     e.unidade = ('grau Celsius', 'graus Celsius')
  639.     e.genero_unidade_masculino = True
  640.     e.precisao_decimal = 1
  641.     e.unidade_decimal = ('décimo', 'décimos')
  642.     e.genero_unidade_decimal_masculino = True
  643.     print('Valor em graus Celsius e décimos (com 1 casa decimais de precisão):', e.extenso_unidade)
  644.  
  645.     e.unidade = ('ponto percentual', 'pontos percentuais')
  646.     e.genero_unidade_masculino = True
  647.     e.precisao_decimal = 0
  648.     print('Valor em pontos percentuais (somente inteiros):', e.extenso_unidade)
  649.  
  650.     e.numero *= -1
  651.     print('Valor em pontos percentuais negativos (somente inteiros):', e.extenso_unidade)
  652.  
  653.     e.unidade = ('grau Celsius', 'graus Celsius')
  654.     e.mascara_negativo = ('%s negativo', '%s negativos')
  655.     print('Valor em graus Celsius negativos:', e.extenso_unidade)
clone this paste RAW Paste Data