numbers.cjs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. 'use strict';
  2. const emoji_convert = require('../convert.cjs');
  3. const emoji_regex_base = require('./base.cjs');
  4. const emoji_data = require('../data.cjs');
  5. function createEmojiRegexItemForNumbers(numbers) {
  6. const utf32 = [];
  7. const utf16 = [];
  8. numbers.sort((a, b) => a - b);
  9. let lastNumber;
  10. for (let i = 0; i < numbers.length; i++) {
  11. const number = numbers[i];
  12. if (number === lastNumber) {
  13. continue;
  14. }
  15. lastNumber = number;
  16. const split = emoji_convert.splitUTF32Number(number);
  17. if (!split) {
  18. utf16.push(number);
  19. continue;
  20. }
  21. const [first, second] = split;
  22. const item = utf32.find((item2) => item2.first === first);
  23. if (item) {
  24. item.second.push(second);
  25. item.numbers.push(number);
  26. } else {
  27. utf32.push({
  28. first,
  29. second: [second],
  30. numbers: [number]
  31. });
  32. }
  33. }
  34. const results = [];
  35. if (utf16.length) {
  36. results.push(emoji_regex_base.createUTF16EmojiRegexItem(utf16));
  37. }
  38. if (utf32.length) {
  39. const utf32Set = [];
  40. for (let i = 0; i < utf32.length; i++) {
  41. const item = utf32[i];
  42. const secondRegex = emoji_regex_base.createUTF16EmojiRegexItem(item.second);
  43. const listItem = utf32Set.find(
  44. (item2) => item2.second.regex === secondRegex.regex
  45. );
  46. if (listItem) {
  47. listItem.first.push(item.first);
  48. listItem.numbers = [...listItem.numbers, ...item.numbers];
  49. } else {
  50. utf32Set.push({
  51. second: secondRegex,
  52. first: [item.first],
  53. numbers: [...item.numbers]
  54. });
  55. }
  56. }
  57. for (let i = 0; i < utf32Set.length; i++) {
  58. const item = utf32Set[i];
  59. const firstRegex = emoji_regex_base.createUTF16EmojiRegexItem(item.first);
  60. const secondRegex = item.second;
  61. results.push(
  62. emoji_regex_base.createSequenceEmojiRegexItem(
  63. [firstRegex, secondRegex],
  64. item.numbers
  65. )
  66. );
  67. }
  68. }
  69. return results.length === 1 ? results[0] : emoji_regex_base.createSetEmojiRegexItem(results);
  70. }
  71. function createRegexForNumbersSequence(numbers, optionalVariations = true) {
  72. const items = [];
  73. for (let i = 0; i < numbers.length; i++) {
  74. const num = numbers[i];
  75. const split = emoji_convert.splitUTF32Number(num);
  76. if (!split) {
  77. const item = emoji_regex_base.createUTF16EmojiRegexItem([num]);
  78. if (optionalVariations && num === emoji_data.vs16Emoji) {
  79. items.push(emoji_regex_base.createOptionalEmojiRegexItem(item));
  80. } else {
  81. items.push(item);
  82. }
  83. } else {
  84. items.push(emoji_regex_base.createUTF16EmojiRegexItem([split[0]]));
  85. items.push(emoji_regex_base.createUTF16EmojiRegexItem([split[1]]));
  86. }
  87. }
  88. if (items.length === 1) {
  89. return items[0];
  90. }
  91. const result = emoji_regex_base.createSequenceEmojiRegexItem(items);
  92. if (numbers.length === 1 && items[0].type === "utf16") {
  93. result.numbers = [...numbers];
  94. }
  95. return result;
  96. }
  97. function optimiseNumbersSet(set) {
  98. const mandatoryMatches = {
  99. numbers: [],
  100. items: []
  101. };
  102. const optionalMatches = {
  103. numbers: [],
  104. items: []
  105. };
  106. const filteredItems = set.sets.filter((item) => {
  107. if (item.type === "optional") {
  108. const parentItem = item.item;
  109. if (parentItem.numbers) {
  110. optionalMatches.items.push(item);
  111. optionalMatches.numbers = optionalMatches.numbers.concat(
  112. parentItem.numbers
  113. );
  114. return false;
  115. }
  116. return true;
  117. }
  118. if (item.numbers) {
  119. mandatoryMatches.items.push(item);
  120. mandatoryMatches.numbers = mandatoryMatches.numbers.concat(
  121. item.numbers
  122. );
  123. return false;
  124. }
  125. return true;
  126. });
  127. if (mandatoryMatches.items.length + optionalMatches.items.length < 2) {
  128. return set;
  129. }
  130. const optionalNumbers = new Set(optionalMatches.numbers);
  131. let foundMatches = false;
  132. mandatoryMatches.numbers = mandatoryMatches.numbers.filter((number) => {
  133. if (optionalNumbers.has(number)) {
  134. foundMatches = true;
  135. return false;
  136. }
  137. return true;
  138. });
  139. if (mandatoryMatches.items.length) {
  140. if (!foundMatches && mandatoryMatches.items.length === 1) {
  141. filteredItems.push(mandatoryMatches.items[0]);
  142. } else if (mandatoryMatches.numbers.length) {
  143. filteredItems.push(
  144. createEmojiRegexItemForNumbers(mandatoryMatches.numbers)
  145. );
  146. }
  147. }
  148. switch (optionalMatches.items.length) {
  149. case 0:
  150. break;
  151. case 1:
  152. filteredItems.push(optionalMatches.items[0]);
  153. break;
  154. default:
  155. filteredItems.push(
  156. emoji_regex_base.createOptionalEmojiRegexItem(
  157. createEmojiRegexItemForNumbers(optionalMatches.numbers)
  158. )
  159. );
  160. }
  161. return filteredItems.length === 1 ? filteredItems[0] : emoji_regex_base.createSetEmojiRegexItem(filteredItems);
  162. }
  163. exports.createEmojiRegexItemForNumbers = createEmojiRegexItemForNumbers;
  164. exports.createRegexForNumbersSequence = createRegexForNumbersSequence;
  165. exports.optimiseNumbersSet = optimiseNumbersSet;