big_number.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. # coding: utf-8
  2. import warnings
  3. from decimal import Decimal
  4. def cn_currency(value, capital=True, prefix=False, classical=None):
  5. """
  6. 人民币数字转汉字表示 Ver 0.02
  7. 作者: qianjin(AT)ustc.edu
  8. 版权声明:
  9. 只要保留本代码最初作者的电子邮件即可,随便用。用得爽的话,不反对请
  10. 作者吃一顿。
  11. 参数:
  12. capital: True 大写汉字金额
  13. False 一般汉字金额
  14. classical: True 圆
  15. False 元
  16. prefix: True 以'人民币'开头
  17. False, 无开头
  18. """
  19. # if not isinstance(value, (Decimal, str, int)):
  20. # msg = u'''
  21. #
  22. # 由于浮点数精度问题,请使用考虑使用字符串,或者 decimal.Decimal 类。
  23. #
  24. # 因使用浮点数造成误差而带来的可能风险和损失作者概不负责。
  25. #
  26. # '''
  27. #
  28. # warnings.warn(msg, UserWarning)
  29. # 默认大写金额用圆,一般汉字金额用元
  30. if classical is None:
  31. classical = True if capital else False
  32. # 汉字金额前缀
  33. if prefix is True:
  34. prefix = '人民币'
  35. else:
  36. prefix = ''
  37. # 汉字金额字符定义
  38. dunit = ('角', '分')
  39. if capital:
  40. num = ('零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖')
  41. iunit = [None, '拾', '佰', '仟', '万', '拾', '佰', '仟',
  42. '亿', '拾', '佰', '仟', '万', '拾', '佰', '仟']
  43. else:
  44. num = ('〇', '一', '二', '三', '四', '五', '六', '七', '八', '九')
  45. iunit = [None, '十', '百', '千', '万', '十', '百', '千',
  46. '亿', '十', '百', '千', '万', '十', '百', '千']
  47. if classical:
  48. iunit[0] = '圆' if classical else '元'
  49. # 转换为Decimal,并截断多余小数
  50. if not isinstance(value, Decimal):
  51. value = Decimal(value).quantize(Decimal('0.01'))
  52. # 处理负数
  53. if value < 0:
  54. prefix += '负' # 输出前缀,加负
  55. value = - value # 取正数部分,无须过多考虑正负数舍入
  56. # assert - value + value == 0
  57. # 转化为字符串
  58. s = str(value)
  59. if len(s) > 19:
  60. raise ValueError('金额太大了,不知道该怎么表达。')
  61. istr, dstr = s.split('.') # 小数部分和整数部分分别处理
  62. istr = istr[::-1] # 翻转整数部分字符串
  63. so = [] # 用于记录转换结果
  64. # 零
  65. if value == 0:
  66. return prefix + num[0] + iunit[0]
  67. haszero = False # 用于标记零的使用
  68. if dstr == '00':
  69. haszero = True # 如果无小数部分,则标记加过零,避免出现“圆零整”
  70. # 处理小数部分
  71. # 分
  72. if dstr[1] != '0':
  73. so.append(dunit[1])
  74. so.append(num[int(dstr[1])])
  75. else:
  76. so.append('整') # 无分,则加“整”
  77. # 角
  78. if dstr[0] != '0':
  79. so.append(dunit[0])
  80. so.append(num[int(dstr[0])])
  81. elif dstr[1] != '0':
  82. so.append(num[0]) # 无角有分,添加“零”
  83. haszero = True # 标记加过零了
  84. # 无整数部分
  85. if istr == '0':
  86. if haszero: # 既然无整数部分,那么去掉角位置上的零
  87. so.pop()
  88. so.append(prefix) # 加前缀
  89. so.reverse() # 翻转
  90. return ''.join(so)
  91. # 处理整数部分
  92. for i, n in enumerate(istr):
  93. n = int(n)
  94. if i % 4 == 0: # 在圆、万、亿等位上,即使是零,也必须有单位
  95. if i == 8 and so[-1] == iunit[4]: # 亿和万之间全部为零的情况
  96. so.pop() # 去掉万
  97. so.append(iunit[i])
  98. if n == 0: # 处理这些位上为零的情况
  99. if not haszero: # 如果以前没有加过零
  100. so.insert(-1, num[0]) # 则在单位后面加零
  101. haszero = True # 标记加过零了
  102. else: # 处理不为零的情况
  103. so.append(num[n])
  104. haszero = False # 重新开始标记加零的情况
  105. else: # 在其他位置上
  106. if n != 0: # 不为零的情况
  107. so.append(iunit[i])
  108. so.append(num[n])
  109. haszero = False # 重新开始标记加零的情况
  110. else: # 处理为零的情况
  111. if not haszero: # 如果以前没有加过零
  112. so.append(num[0])
  113. haszero = True
  114. # 最终结果
  115. so.append(prefix)
  116. so.reverse()
  117. return ''.join(so)