134 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { vs16Emoji } from "../data.js";
 | |
| import { splitUTF32Number } from "../convert.js";
 | |
| import { createOptionalEmojiRegexItem, createSequenceEmojiRegexItem, createSetEmojiRegexItem, createUTF16EmojiRegexItem } from "./base.js";
 | |
| 
 | |
| /**
 | |
| * Create regex item for set of numbers
 | |
| */
 | |
| function createEmojiRegexItemForNumbers(numbers) {
 | |
| 	const utf32 = [];
 | |
| 	const utf16 = [];
 | |
| 	numbers.sort((a, b) => a - b);
 | |
| 	let lastNumber;
 | |
| 	for (let i = 0; i < numbers.length; i++) {
 | |
| 		const number = numbers[i];
 | |
| 		if (number === lastNumber) continue;
 | |
| 		lastNumber = number;
 | |
| 		const split = splitUTF32Number(number);
 | |
| 		if (!split) {
 | |
| 			utf16.push(number);
 | |
| 			continue;
 | |
| 		}
 | |
| 		const [first, second] = split;
 | |
| 		const item = utf32.find((item$1) => item$1.first === first);
 | |
| 		if (item) {
 | |
| 			item.second.push(second);
 | |
| 			item.numbers.push(number);
 | |
| 		} else utf32.push({
 | |
| 			first,
 | |
| 			second: [second],
 | |
| 			numbers: [number]
 | |
| 		});
 | |
| 	}
 | |
| 	const results = [];
 | |
| 	if (utf16.length) results.push(createUTF16EmojiRegexItem(utf16));
 | |
| 	if (utf32.length) {
 | |
| 		const utf32Set = [];
 | |
| 		for (let i = 0; i < utf32.length; i++) {
 | |
| 			const item = utf32[i];
 | |
| 			const secondRegex = createUTF16EmojiRegexItem(item.second);
 | |
| 			const listItem = utf32Set.find((item$1) => item$1.second.regex === secondRegex.regex);
 | |
| 			if (listItem) {
 | |
| 				listItem.first.push(item.first);
 | |
| 				listItem.numbers = [...listItem.numbers, ...item.numbers];
 | |
| 			} else utf32Set.push({
 | |
| 				second: secondRegex,
 | |
| 				first: [item.first],
 | |
| 				numbers: [...item.numbers]
 | |
| 			});
 | |
| 		}
 | |
| 		for (let i = 0; i < utf32Set.length; i++) {
 | |
| 			const item = utf32Set[i];
 | |
| 			const firstRegex = createUTF16EmojiRegexItem(item.first);
 | |
| 			const secondRegex = item.second;
 | |
| 			results.push(createSequenceEmojiRegexItem([firstRegex, secondRegex], item.numbers));
 | |
| 		}
 | |
| 	}
 | |
| 	return results.length === 1 ? results[0] : createSetEmojiRegexItem(results);
 | |
| }
 | |
| /**
 | |
| * Create sequence of numbers
 | |
| */
 | |
| function createRegexForNumbersSequence(numbers, optionalVariations = true) {
 | |
| 	const items = [];
 | |
| 	for (let i = 0; i < numbers.length; i++) {
 | |
| 		const num = numbers[i];
 | |
| 		const split = splitUTF32Number(num);
 | |
| 		if (!split) {
 | |
| 			const item = createUTF16EmojiRegexItem([num]);
 | |
| 			if (optionalVariations && num === vs16Emoji) items.push(createOptionalEmojiRegexItem(item));
 | |
| 			else items.push(item);
 | |
| 		} else {
 | |
| 			items.push(createUTF16EmojiRegexItem([split[0]]));
 | |
| 			items.push(createUTF16EmojiRegexItem([split[1]]));
 | |
| 		}
 | |
| 	}
 | |
| 	if (items.length === 1) return items[0];
 | |
| 	const result = createSequenceEmojiRegexItem(items);
 | |
| 	if (numbers.length === 1 && items[0].type === "utf16") result.numbers = [...numbers];
 | |
| 	return result;
 | |
| }
 | |
| /**
 | |
| * Attempt to optimise numbers in a set
 | |
| */
 | |
| function optimiseNumbersSet(set) {
 | |
| 	const mandatoryMatches = {
 | |
| 		numbers: [],
 | |
| 		items: []
 | |
| 	};
 | |
| 	const optionalMatches = {
 | |
| 		numbers: [],
 | |
| 		items: []
 | |
| 	};
 | |
| 	const filteredItems = set.sets.filter((item) => {
 | |
| 		if (item.type === "optional") {
 | |
| 			const parentItem = item.item;
 | |
| 			if (parentItem.numbers) {
 | |
| 				optionalMatches.items.push(item);
 | |
| 				optionalMatches.numbers = optionalMatches.numbers.concat(parentItem.numbers);
 | |
| 				return false;
 | |
| 			}
 | |
| 			return true;
 | |
| 		}
 | |
| 		if (item.numbers) {
 | |
| 			mandatoryMatches.items.push(item);
 | |
| 			mandatoryMatches.numbers = mandatoryMatches.numbers.concat(item.numbers);
 | |
| 			return false;
 | |
| 		}
 | |
| 		return true;
 | |
| 	});
 | |
| 	if (mandatoryMatches.items.length + optionalMatches.items.length < 2) return set;
 | |
| 	const optionalNumbers = new Set(optionalMatches.numbers);
 | |
| 	let foundMatches = false;
 | |
| 	mandatoryMatches.numbers = mandatoryMatches.numbers.filter((number) => {
 | |
| 		if (optionalNumbers.has(number)) {
 | |
| 			foundMatches = true;
 | |
| 			return false;
 | |
| 		}
 | |
| 		return true;
 | |
| 	});
 | |
| 	if (mandatoryMatches.items.length) {
 | |
| 		if (!foundMatches && mandatoryMatches.items.length === 1) filteredItems.push(mandatoryMatches.items[0]);
 | |
| 		else if (mandatoryMatches.numbers.length) filteredItems.push(createEmojiRegexItemForNumbers(mandatoryMatches.numbers));
 | |
| 	}
 | |
| 	switch (optionalMatches.items.length) {
 | |
| 		case 0: break;
 | |
| 		case 1:
 | |
| 			filteredItems.push(optionalMatches.items[0]);
 | |
| 			break;
 | |
| 		default: filteredItems.push(createOptionalEmojiRegexItem(createEmojiRegexItemForNumbers(optionalMatches.numbers)));
 | |
| 	}
 | |
| 	return filteredItems.length === 1 ? filteredItems[0] : createSetEmojiRegexItem(filteredItems);
 | |
| }
 | |
| 
 | |
| export { createEmojiRegexItemForNumbers, createRegexForNumbersSequence, optimiseNumbersSet }; | 
