Gets the name of a number, even if it's stupidly big. Supersedes TheoryOfNekomata/number-name.
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

177 строки
4.2 KiB

  1. type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
  2. /**
  3. * Group digits.
  4. */
  5. export type GroupDigits = `${Digit}${Digit}${Digit}`;
  6. /**
  7. * Group place.
  8. */
  9. export type GroupPlace = bigint;
  10. /**
  11. * Group of digits and its place.
  12. *
  13. * The place refers to the order which the digits are grouped, e.g. for a number like
  14. *
  15. * 1,234,567
  16. *
  17. * The groups would be:
  18. *
  19. * ['001', 2]
  20. * ['234', 1]
  21. * ['567', 0]
  22. *
  23. * Note that groups do not necessarily have the same length of digits, such in the case of
  24. * South Asian numbering system:
  25. *
  26. * 1,00,00,000
  27. *
  28. * The groups would be:
  29. *
  30. * ['01', 3]
  31. * ['00', 2]
  32. * ['00', 1]
  33. * ['000', 0]
  34. */
  35. export type Group = [GroupDigits, GroupPlace];
  36. /**
  37. * Index of the group digits in a {@link Group|group}.
  38. */
  39. export const GROUP_DIGITS_INDEX = 0 as const;
  40. /**
  41. * Index of the group place in a {@link Group|group}.
  42. */
  43. export const GROUP_PLACE_INDEX = 1 as const;
  44. /**
  45. * Result of parsing a number string.
  46. */
  47. export interface ParseResult {
  48. /**
  49. * The parsed groups.
  50. */
  51. groups: Group[];
  52. /**
  53. * Whether the number is negative.
  54. */
  55. negative: boolean;
  56. }
  57. /**
  58. * System for stringifying and parsing numbers.
  59. */
  60. export interface NumberNameSystem {
  61. /**
  62. * Creates a negative string.
  63. * @param s - The string to make negative.
  64. * @returns string The negative string.
  65. */
  66. makeNegative: (s: string) => string;
  67. /**
  68. * Splits a string into groups.
  69. * @param value - The string to group.
  70. * @see {NumberNameSystem.combineGroups}
  71. * @returns Group[] The groups.
  72. */
  73. splitIntoGroups: (value: string) => Group[];
  74. /**
  75. * Creates a group string.
  76. * @param groups - The groups.
  77. * @param options - Options to use when creating the group.
  78. * @see {NumberNameSystem.parseGroups}
  79. * @returns string[] The groups represented into strings.
  80. */
  81. stringifyGroups: <T extends object>(groups: Group[], options?: T) => string[];
  82. /**
  83. * Merges tokens from stringified groups to a string.
  84. * @param tokens - The tokens to finalize.
  85. * @see {NumberNameSystem.tokenize}
  86. * @returns string The merged tokens.
  87. */
  88. mergeTokens: <T extends object>(tokens: string[], options?: T) => string;
  89. /**
  90. * Tokenizes a string.
  91. * @param value - The string to tokenize.
  92. * @see {NumberNameSystem.mergeTokens}
  93. * @returns string[] The tokens.
  94. */
  95. tokenize: (value: string) => string[];
  96. /**
  97. * Parses groups from a string.
  98. * @param tokens - The string to parse groups from.
  99. * @see {NumberNameSystem.stringifyGroups}
  100. * @returns ParseResult The parsed groups as well as an indicator if the number is Boolean.
  101. */
  102. parseGroups: (tokens: string[]) => ParseResult;
  103. /**
  104. * Combines groups into a string.
  105. * @param groups - The groups to combine.
  106. * @param negative - Whether the number is negative.
  107. * @see {NumberNameSystem.splitIntoGroups}
  108. * @returns string The combined groups in exponential form.
  109. */
  110. combineGroups: (groups: Group[], negative: boolean) => string;
  111. }
  112. /**
  113. * Allowed value type for {@link stringify}.
  114. */
  115. export type AllowedValue = string | number | bigint;
  116. /**
  117. * Array of allowed types for {@link parse}.
  118. */
  119. export const ALLOWED_PARSE_RESULT_TYPES = [
  120. 'string',
  121. 'number',
  122. 'bigint',
  123. ] as const;
  124. /**
  125. * Allowed type for {@link parse}.
  126. */
  127. export type ParseResultType = typeof ALLOWED_PARSE_RESULT_TYPES[number];
  128. /**
  129. * Error thrown when an invalid token is encountered.
  130. */
  131. export class InvalidTokenError extends Error {
  132. constructor(token: string) {
  133. super(`Invalid token: ${token}`);
  134. }
  135. }
  136. /**
  137. * Gets the maximum value from a list of bigints.
  138. * @param b - The bigints to get the maximum value from.
  139. * @returns bigint The maximum value.
  140. */
  141. export const bigIntMax = (...b: bigint[]) => b.reduce(
  142. (previousMax, current) => {
  143. if (typeof previousMax === 'undefined') {
  144. return current;
  145. }
  146. return previousMax > current ? previousMax : current;
  147. },
  148. undefined as bigint | undefined,
  149. );
  150. /**
  151. * Gets the minimum value from a list of bigints.
  152. * @param b - The bigints to get the minimum value from.
  153. * @returns bigint The minimum value.
  154. */
  155. export const bigIntMin = (...b: bigint[]) => b.reduce(
  156. (previousMin, current) => {
  157. if (typeof previousMin === 'undefined') {
  158. return current;
  159. }
  160. return previousMin < current ? previousMin : current;
  161. },
  162. undefined as bigint | undefined,
  163. );