Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

numberformat.py 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. from decimal import Decimal
  2. from django.conf import settings
  3. from django.utils.safestring import mark_safe
  4. def format(
  5. number,
  6. decimal_sep,
  7. decimal_pos=None,
  8. grouping=0,
  9. thousand_sep="",
  10. force_grouping=False,
  11. use_l10n=None,
  12. ):
  13. """
  14. Get a number (as a number or string), and return it as a string,
  15. using formats defined as arguments:
  16. * decimal_sep: Decimal separator symbol (for example ".")
  17. * decimal_pos: Number of decimal positions
  18. * grouping: Number of digits in every group limited by thousand separator.
  19. For non-uniform digit grouping, it can be a sequence with the number
  20. of digit group sizes following the format used by the Python locale
  21. module in locale.localeconv() LC_NUMERIC grouping (e.g. (3, 2, 0)).
  22. * thousand_sep: Thousand separator symbol (for example ",")
  23. """
  24. use_grouping = (
  25. use_l10n or (use_l10n is None and settings.USE_L10N)
  26. ) and settings.USE_THOUSAND_SEPARATOR
  27. use_grouping = use_grouping or force_grouping
  28. use_grouping = use_grouping and grouping != 0
  29. # Make the common case fast
  30. if isinstance(number, int) and not use_grouping and not decimal_pos:
  31. return mark_safe(number)
  32. # sign
  33. sign = ""
  34. # Treat potentially very large/small floats as Decimals.
  35. if isinstance(number, float) and "e" in str(number).lower():
  36. number = Decimal(str(number))
  37. if isinstance(number, Decimal):
  38. if decimal_pos is not None:
  39. # If the provided number is too small to affect any of the visible
  40. # decimal places, consider it equal to '0'.
  41. cutoff = Decimal("0." + "1".rjust(decimal_pos, "0"))
  42. if abs(number) < cutoff:
  43. number = Decimal("0")
  44. # Format values with more than 200 digits (an arbitrary cutoff) using
  45. # scientific notation to avoid high memory usage in {:f}'.format().
  46. _, digits, exponent = number.as_tuple()
  47. if abs(exponent) + len(digits) > 200:
  48. number = "{:e}".format(number)
  49. coefficient, exponent = number.split("e")
  50. # Format the coefficient.
  51. coefficient = format(
  52. coefficient,
  53. decimal_sep,
  54. decimal_pos,
  55. grouping,
  56. thousand_sep,
  57. force_grouping,
  58. use_l10n,
  59. )
  60. return "{}e{}".format(coefficient, exponent)
  61. else:
  62. str_number = "{:f}".format(number)
  63. else:
  64. str_number = str(number)
  65. if str_number[0] == "-":
  66. sign = "-"
  67. str_number = str_number[1:]
  68. # decimal part
  69. if "." in str_number:
  70. int_part, dec_part = str_number.split(".")
  71. if decimal_pos is not None:
  72. dec_part = dec_part[:decimal_pos]
  73. else:
  74. int_part, dec_part = str_number, ""
  75. if decimal_pos is not None:
  76. dec_part = dec_part + ("0" * (decimal_pos - len(dec_part)))
  77. dec_part = dec_part and decimal_sep + dec_part
  78. # grouping
  79. if use_grouping:
  80. try:
  81. # if grouping is a sequence
  82. intervals = list(grouping)
  83. except TypeError:
  84. # grouping is a single value
  85. intervals = [grouping, 0]
  86. active_interval = intervals.pop(0)
  87. int_part_gd = ""
  88. cnt = 0
  89. for digit in int_part[::-1]:
  90. if cnt and cnt == active_interval:
  91. if intervals:
  92. active_interval = intervals.pop(0) or active_interval
  93. int_part_gd += thousand_sep[::-1]
  94. cnt = 0
  95. int_part_gd += digit
  96. cnt += 1
  97. int_part = int_part_gd[::-1]
  98. return sign + int_part + dec_part