var fs = require('fs'); var regexpu = require('regexpu'); // Generate a map of all codes that appear in emojis var emojiCodesMap = {}; (function () { var emojiTestData = fs.readFileSync('./emoji-test.txt').toString('utf8'); var emojiTestEntries = emojiTestData.split('\n'); for (var i = 0, len = emojiTestEntries.length; i < len; i++) { var entry = emojiTestEntries[i]; // strip comments entry = entry.replace(/#.*/, ''); entry = entry.trim(); // strip status entry = entry.replace(/;.*/, ''); entry = entry.trim(); if (entry.indexOf(' ') > 0) { // ignore combined continue; } if (entry.length === 0) { // ignore empty lines continue; } emojiCodesMap[parseInt(entry, 16)] = true; } })(); function toUnicodeCode(n) { return n.toString(16).toUpperCase(); } // Read entire UnicodeData.txt and find contiguous ranges of emojis var emojiCodes = []; var BREAK_SIGNAL = -1; (function () { var data = fs.readFileSync('./UnicodeData.txt').toString('utf8'); var entries = data.split('\n'); var prevWasEmoji = false; for (var i = 0, len = entries.length; i < len; i++) { var entry = entries[i]; var props = entry.split(';'); var code = parseInt(props[0], 16); var _isEmoji = isEmoji(code, emojiCodesMap[code]); if (_isEmoji) { emojiCodes.push(code); prevWasEmoji = true; } else if (prevWasEmoji) { prevWasEmoji = false; emojiCodes.push(BREAK_SIGNAL); } } fs.writeFileSync('emoji-codes.txt', emojiCodes.filter(code => code !== BREAK_SIGNAL).map(toUnicodeCode).join('\n')); })(); var emojiCodeRanges = []; (function () { var startCode = emojiCodes[0]; var prevCode = emojiCodes[0]; for (var i = 1; i < emojiCodes.length; i++) { var code = emojiCodes[i]; if (code === BREAK_SIGNAL) { continue; } if (prevCode + 1 !== code) { emojiCodeRanges.push({ from: startCode, to: prevCode }); startCode = code; } prevCode = code; } emojiCodeRanges.push({ from: startCode, to: prevCode }); })(); fs.writeFileSync('emoji-code-ranges.txt', emojiCodeRanges.map(function (entry) { var from = toUnicodeCode(entry.from); var to = toUnicodeCode(entry.to); if (from === to) { return from; } return from + '-' + to; }).join('\n')); var fuzzy = [], fuzzyLength = 0, breakSignal = false; fuzzy[fuzzyLength++] = { from: emojiCodes[0], to: emojiCodes[0] }; for (var i = 1; i < emojiCodes.length; i++) { var code = emojiCodes[i]; if (code === BREAK_SIGNAL) { breakSignal = true; continue; } if (breakSignal) { fuzzy[fuzzyLength++] = { from: code, to: code }; } else { fuzzy[fuzzyLength - 1].to = code; } breakSignal = false; } fs.writeFileSync('emoji-code-ranges-fuzzy.txt', fuzzy.map(function (entry) { var from = toUnicodeCode(entry.from); var to = toUnicodeCode(entry.to); if (from === to) { return from; } return from + '-' + to; }).join('\n')); var isEmojiFuzzy = fuzzy.map(function(entry) { var from = '\\u{'+toUnicodeCode(entry.from)+'}'; var to = '\\u{'+toUnicodeCode(entry.to)+'}'; if (from === to) { return from; } return from + '-' + to; }).join(''); var isEmojiVeryImprecise = fuzzy.map(function(entry) { if (entry.from + 1 === entry.to) { return `(x === ${entry.from}) || (x === ${entry.to})`; } if (entry.from === entry.to) { return `(x === ${entry.from})`; } return `(x >= ${entry.from} && x <= ${entry.to})`; }).join(' || '); console.log('very imprecise test :: (x >= 0x1F1E6 && x <= 0x1F1FF) || ' + isEmojiVeryImprecise); // Flags use two code points, but they usually start with 1F1E6 - 1F1FF // REGIONAL INDICATOR SYMBOL LETTER A -> REGIONAL INDICATOR SYMBOL LETTER Z isEmojiFuzzy += '\\u{1F1E6}-\\u{1F1FF}'; // TODO: // use U+FE0F as a hint // http://emojipedia.org/variation-selector-16/ // Variation Selector-16 // An invisible codepoint which specifies that the preceding character should be displayed with emoji presentation. Only required if the preceding character defaults to text presentation. var regex = '[' + isEmojiFuzzy + ']'; console.log('UNICODE CODE-POINTS RANGES:'); console.log(regex); var r = regexpu.rewritePattern(regex, 'u'); console.log('------'); console.log(r); console.log('------'); // GOTTEN FROM ABOVE RESULT var containsEmoji = /(?:[\u231A\u231B\u23F0\u23F3\u2600-\u27BF\u2B50\u2B55]|\uD83C[\uDDE6-\uDDFF\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F\uDE80-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD00-\uDDFF\uDE70-\uDED6])/; // SANITY CHECK the regex (function () { var emojiTestData = fs.readFileSync('./emoji-test.txt').toString('utf8'); var emojiTestEntries = emojiTestData.split('\n'); var MISSING = []; for (var i = 0, len = emojiTestEntries.length; i < len; i++) { var original = emojiTestEntries[i]; var entry = emojiTestEntries[i]; // strip comments entry = entry.replace(/#.*/, ''); entry = entry.trim(); // strip status entry = entry.replace(/;.*/, ''); entry = entry.trim(); if (entry.length === 0) { // ignore empty lines continue; } var codes = entry.split(' ').map(function(code) { return parseInt(code, 16); }); var str = 'some '; for (var j = 0; j < codes.length; j++) { str += String.fromCodePoint(codes[j]); } str += ' text'; if (containsEmoji.test(str)) { // regex captures this input continue; } MISSING.push(original); // MISSING.push('TEST STRING: <<' + str + '>>'); // console.log(str); // String.fromCodePoint() // console.log(entry); // if (entry.indexOf(' ') > 0) { // // ignore combined // continue; // } // if (entry.length === 0) { // // ignore empty lines // continue; // } // emojiCodesMap[parseInt(entry, 16)] = true; } fs.writeFileSync('emoji-missed.txt', 'THE FOLLOWING ARE NOT CAPTURED BY THE REGEX: \n' + MISSING.join('\n')); // console.log(MISSING); })(); function isEmoji(code, isInEmojiTest) { var block = getCodeBlock(code); // Exclude some codes in emoji-test.txt that don't look like emojis. if (block === 'Latin-1 Supplement') { // e.g. 00A9 © copyright return false; } if (block === 'General Punctuation') { // e.g. 203C ‼️ double exclamation mark return false; } if (block === 'Letterlike Symbols') { // e.g. 2122 ️️™️ trade mark return false; } if (block === 'Arrows') { // e.g. 2194 ↔ left-right arrow return false; } if (block === 'Miscellaneous Technical') { // U+2300 -> U+23FE if (code === 0x231A) { // ⌚ watch return true; } if (code === 0x231B) { // ⌛ hourglass return true; } if (code === 0x23F0) { // ⏰ alarm clock return true; } if (code === 0x23F3) { // ⏳ hourglass with flowing sand return true; } return false; } if (block === 'Enclosed Alphanumerics') { // e.g. 24C2 Ⓜ circled M return false; } if (block === 'Geometric Shapes') { // e.g. 25AA ▪ black small square return false; } if (block === 'Supplemental Arrows-B') { // e.g. 2934 ⤴ right arrow curving up return false; } if (block === 'Miscellaneous Symbols and Arrows') { if (code === 0x2B50) { // ⭐ white medium star return true; } if (code === 0x2B55) { // ⭕ heavy large circle return true; } return false; } if (block === 'CJK Symbols and Punctuation') { // e.g. 303D 〽 part alternation mark return false; } if (block === 'Enclosed CJK Letters and Months') { // e.g. 3297 ㊗ Japanese “congratulations” button return false; } if (block === 'Mahjong Tiles') { // e.g. 1F004 🀄 mahjong red dragon return false; } if (block === 'Playing Cards') { // e.g. 1F0CF 🃏 joker return false; } if (block === 'Enclosed Alphanumeric Supplement') { // e.g. 1F170 🅰 A button (blood type) return false; } if (block === 'Enclosed Ideographic Supplement') { // e.g. 1F201 🈁 Japanese “here” button return false; } // include some blocks that look like emojis if (block === 'Miscellaneous Symbols') { return true; } if (block === 'Dingbats') { return true; } if (block === 'Miscellaneous Symbols and Pictographs') { return true; } if (block === 'Emoticons') { return true; } if (block === 'Transport and Map Symbols') { return true; } if (block === 'Supplemental Symbols and Pictographs') { return true; } return isInEmojiTest; } // http://www.fileformat.info/info/unicode/block/index.htm // replace ^([^\t]+)\tU\+([0-9A-Z]+)\tU\+([0-9A-Z]+) // with if (code >= 0x$2 && code <= 0x$3) return '$1'; function getCodeBlock(code) { if (code >= 0x0000 && code <= 0x007F) return 'Basic Latin'; if (code >= 0x0080 && code <= 0x00FF) return 'Latin-1 Supplement'; if (code >= 0x0100 && code <= 0x017F) return 'Latin Extended-A'; if (code >= 0x0180 && code <= 0x024F) return 'Latin Extended-B'; if (code >= 0x0250 && code <= 0x02AF) return 'IPA Extensions'; if (code >= 0x02B0 && code <= 0x02FF) return 'Spacing Modifier Letters'; if (code >= 0x0300 && code <= 0x036F) return 'Combining Diacritical Marks'; if (code >= 0x0370 && code <= 0x03FF) return 'Greek and Coptic'; if (code >= 0x0400 && code <= 0x04FF) return 'Cyrillic'; if (code >= 0x0500 && code <= 0x052F) return 'Cyrillic Supplement'; if (code >= 0x0530 && code <= 0x058F) return 'Armenian'; if (code >= 0x0590 && code <= 0x05FF) return 'Hebrew'; if (code >= 0x0600 && code <= 0x06FF) return 'Arabic'; if (code >= 0x0700 && code <= 0x074F) return 'Syriac'; if (code >= 0x0750 && code <= 0x077F) return 'Arabic Supplement'; if (code >= 0x0780 && code <= 0x07BF) return 'Thaana'; if (code >= 0x07C0 && code <= 0x07FF) return 'NKo'; if (code >= 0x0800 && code <= 0x083F) return 'Samaritan'; if (code >= 0x0840 && code <= 0x085F) return 'Mandaic'; if (code >= 0x08A0 && code <= 0x08FF) return 'Arabic Extended-A'; if (code >= 0x0900 && code <= 0x097F) return 'Devanagari'; if (code >= 0x0980 && code <= 0x09FF) return 'Bengali'; if (code >= 0x0A00 && code <= 0x0A7F) return 'Gurmukhi'; if (code >= 0x0A80 && code <= 0x0AFF) return 'Gujarati'; if (code >= 0x0B00 && code <= 0x0B7F) return 'Oriya'; if (code >= 0x0B80 && code <= 0x0BFF) return 'Tamil'; if (code >= 0x0C00 && code <= 0x0C7F) return 'Telugu'; if (code >= 0x0C80 && code <= 0x0CFF) return 'Kannada'; if (code >= 0x0D00 && code <= 0x0D7F) return 'Malayalam'; if (code >= 0x0D80 && code <= 0x0DFF) return 'Sinhala'; if (code >= 0x0E00 && code <= 0x0E7F) return 'Thai'; if (code >= 0x0E80 && code <= 0x0EFF) return 'Lao'; if (code >= 0x0F00 && code <= 0x0FFF) return 'Tibetan'; if (code >= 0x1000 && code <= 0x109F) return 'Myanmar'; if (code >= 0x10A0 && code <= 0x10FF) return 'Georgian'; if (code >= 0x1100 && code <= 0x11FF) return 'Hangul Jamo'; if (code >= 0x1200 && code <= 0x137F) return 'Ethiopic'; if (code >= 0x1380 && code <= 0x139F) return 'Ethiopic Supplement'; if (code >= 0x13A0 && code <= 0x13FF) return 'Cherokee'; if (code >= 0x1400 && code <= 0x167F) return 'Unified Canadian Aboriginal Syllabics'; if (code >= 0x1680 && code <= 0x169F) return 'Ogham'; if (code >= 0x16A0 && code <= 0x16FF) return 'Runic'; if (code >= 0x1700 && code <= 0x171F) return 'Tagalog'; if (code >= 0x1720 && code <= 0x173F) return 'Hanunoo'; if (code >= 0x1740 && code <= 0x175F) return 'Buhid'; if (code >= 0x1760 && code <= 0x177F) return 'Tagbanwa'; if (code >= 0x1780 && code <= 0x17FF) return 'Khmer'; if (code >= 0x1800 && code <= 0x18AF) return 'Mongolian'; if (code >= 0x18B0 && code <= 0x18FF) return 'Unified Canadian Aboriginal Syllabics Extended'; if (code >= 0x1900 && code <= 0x194F) return 'Limbu'; if (code >= 0x1950 && code <= 0x197F) return 'Tai Le'; if (code >= 0x1980 && code <= 0x19DF) return 'New Tai Lue'; if (code >= 0x19E0 && code <= 0x19FF) return 'Khmer Symbols'; if (code >= 0x1A00 && code <= 0x1A1F) return 'Buginese'; if (code >= 0x1A20 && code <= 0x1AAF) return 'Tai Tham'; if (code >= 0x1AB0 && code <= 0x1AFF) return 'Combining Diacritical Marks Extended'; if (code >= 0x1B00 && code <= 0x1B7F) return 'Balinese'; if (code >= 0x1B80 && code <= 0x1BBF) return 'Sundanese'; if (code >= 0x1BC0 && code <= 0x1BFF) return 'Batak'; if (code >= 0x1C00 && code <= 0x1C4F) return 'Lepcha'; if (code >= 0x1C50 && code <= 0x1C7F) return 'Ol Chiki'; if (code >= 0x1C80 && code <= 0x1C8F) return 'Cyrillic Extended-C'; if (code >= 0x1CC0 && code <= 0x1CCF) return 'Sundanese Supplement'; if (code >= 0x1CD0 && code <= 0x1CFF) return 'Vedic Extensions'; if (code >= 0x1D00 && code <= 0x1D7F) return 'Phonetic Extensions'; if (code >= 0x1D80 && code <= 0x1DBF) return 'Phonetic Extensions Supplement'; if (code >= 0x1DC0 && code <= 0x1DFF) return 'Combining Diacritical Marks Supplement'; if (code >= 0x1E00 && code <= 0x1EFF) return 'Latin Extended Additional'; if (code >= 0x1F00 && code <= 0x1FFF) return 'Greek Extended'; if (code >= 0x2000 && code <= 0x206F) return 'General Punctuation'; if (code >= 0x2070 && code <= 0x209F) return 'Superscripts and Subscripts'; if (code >= 0x20A0 && code <= 0x20CF) return 'Currency Symbols'; if (code >= 0x20D0 && code <= 0x20FF) return 'Combining Diacritical Marks for Symbols'; if (code >= 0x2100 && code <= 0x214F) return 'Letterlike Symbols'; if (code >= 0x2150 && code <= 0x218F) return 'Number Forms'; if (code >= 0x2190 && code <= 0x21FF) return 'Arrows'; if (code >= 0x2200 && code <= 0x22FF) return 'Mathematical Operators'; if (code >= 0x2300 && code <= 0x23FF) return 'Miscellaneous Technical'; if (code >= 0x2400 && code <= 0x243F) return 'Control Pictures'; if (code >= 0x2440 && code <= 0x245F) return 'Optical Character Recognition'; if (code >= 0x2460 && code <= 0x24FF) return 'Enclosed Alphanumerics'; if (code >= 0x2500 && code <= 0x257F) return 'Box Drawing'; if (code >= 0x2580 && code <= 0x259F) return 'Block Elements'; if (code >= 0x25A0 && code <= 0x25FF) return 'Geometric Shapes'; if (code >= 0x2600 && code <= 0x26FF) return 'Miscellaneous Symbols'; if (code >= 0x2700 && code <= 0x27BF) return 'Dingbats'; if (code >= 0x27C0 && code <= 0x27EF) return 'Miscellaneous Mathematical Symbols-A'; if (code >= 0x27F0 && code <= 0x27FF) return 'Supplemental Arrows-A'; if (code >= 0x2800 && code <= 0x28FF) return 'Braille Patterns'; if (code >= 0x2900 && code <= 0x297F) return 'Supplemental Arrows-B'; if (code >= 0x2980 && code <= 0x29FF) return 'Miscellaneous Mathematical Symbols-B'; if (code >= 0x2A00 && code <= 0x2AFF) return 'Supplemental Mathematical Operators'; if (code >= 0x2B00 && code <= 0x2BFF) return 'Miscellaneous Symbols and Arrows'; if (code >= 0x2C00 && code <= 0x2C5F) return 'Glagolitic'; if (code >= 0x2C60 && code <= 0x2C7F) return 'Latin Extended-C'; if (code >= 0x2C80 && code <= 0x2CFF) return 'Coptic'; if (code >= 0x2D00 && code <= 0x2D2F) return 'Georgian Supplement'; if (code >= 0x2D30 && code <= 0x2D7F) return 'Tifinagh'; if (code >= 0x2D80 && code <= 0x2DDF) return 'Ethiopic Extended'; if (code >= 0x2DE0 && code <= 0x2DFF) return 'Cyrillic Extended-A'; if (code >= 0x2E00 && code <= 0x2E7F) return 'Supplemental Punctuation'; if (code >= 0x2E80 && code <= 0x2EFF) return 'CJK Radicals Supplement'; if (code >= 0x2F00 && code <= 0x2FDF) return 'Kangxi Radicals'; if (code >= 0x2FF0 && code <= 0x2FFF) return 'Ideographic Description Characters'; if (code >= 0x3000 && code <= 0x303F) return 'CJK Symbols and Punctuation'; if (code >= 0x3040 && code <= 0x309F) return 'Hiragana'; if (code >= 0x30A0 && code <= 0x30FF) return 'Katakana'; if (code >= 0x3100 && code <= 0x312F) return 'Bopomofo'; if (code >= 0x3130 && code <= 0x318F) return 'Hangul Compatibility Jamo'; if (code >= 0x3190 && code <= 0x319F) return 'Kanbun'; if (code >= 0x31A0 && code <= 0x31BF) return 'Bopomofo Extended'; if (code >= 0x31C0 && code <= 0x31EF) return 'CJK Strokes'; if (code >= 0x31F0 && code <= 0x31FF) return 'Katakana Phonetic Extensions'; if (code >= 0x3200 && code <= 0x32FF) return 'Enclosed CJK Letters and Months'; if (code >= 0x3300 && code <= 0x33FF) return 'CJK Compatibility'; if (code >= 0x3400 && code <= 0x4DBF) return 'CJK Unified Ideographs Extension A'; if (code >= 0x4DC0 && code <= 0x4DFF) return 'Yijing Hexagram Symbols'; if (code >= 0x4E00 && code <= 0x9FFF) return 'CJK Unified Ideographs'; if (code >= 0xA000 && code <= 0xA48F) return 'Yi Syllables'; if (code >= 0xA490 && code <= 0xA4CF) return 'Yi Radicals'; if (code >= 0xA4D0 && code <= 0xA4FF) return 'Lisu'; if (code >= 0xA500 && code <= 0xA63F) return 'Vai'; if (code >= 0xA640 && code <= 0xA69F) return 'Cyrillic Extended-B'; if (code >= 0xA6A0 && code <= 0xA6FF) return 'Bamum'; if (code >= 0xA700 && code <= 0xA71F) return 'Modifier Tone Letters'; if (code >= 0xA720 && code <= 0xA7FF) return 'Latin Extended-D'; if (code >= 0xA800 && code <= 0xA82F) return 'Syloti Nagri'; if (code >= 0xA830 && code <= 0xA83F) return 'Common Indic Number Forms'; if (code >= 0xA840 && code <= 0xA87F) return 'Phags-pa'; if (code >= 0xA880 && code <= 0xA8DF) return 'Saurashtra'; if (code >= 0xA8E0 && code <= 0xA8FF) return 'Devanagari Extended'; if (code >= 0xA900 && code <= 0xA92F) return 'Kayah Li'; if (code >= 0xA930 && code <= 0xA95F) return 'Rejang'; if (code >= 0xA960 && code <= 0xA97F) return 'Hangul Jamo Extended-A'; if (code >= 0xA980 && code <= 0xA9DF) return 'Javanese'; if (code >= 0xA9E0 && code <= 0xA9FF) return 'Myanmar Extended-B'; if (code >= 0xAA00 && code <= 0xAA5F) return 'Cham'; if (code >= 0xAA60 && code <= 0xAA7F) return 'Myanmar Extended-A'; if (code >= 0xAA80 && code <= 0xAADF) return 'Tai Viet'; if (code >= 0xAAE0 && code <= 0xAAFF) return 'Meetei Mayek Extensions'; if (code >= 0xAB00 && code <= 0xAB2F) return 'Ethiopic Extended-A'; if (code >= 0xAB30 && code <= 0xAB6F) return 'Latin Extended-E'; if (code >= 0xAB70 && code <= 0xABBF) return 'Cherokee Supplement'; if (code >= 0xABC0 && code <= 0xABFF) return 'Meetei Mayek'; if (code >= 0xAC00 && code <= 0xD7AF) return 'Hangul Syllables'; if (code >= 0xD7B0 && code <= 0xD7FF) return 'Hangul Jamo Extended-B'; if (code >= 0xD800 && code <= 0xDB7F) return 'High Surrogates'; if (code >= 0xDB80 && code <= 0xDBFF) return 'High Private Use Surrogates'; if (code >= 0xDC00 && code <= 0xDFFF) return 'Low Surrogates'; if (code >= 0xE000 && code <= 0xF8FF) return 'Private Use Area'; if (code >= 0xF900 && code <= 0xFAFF) return 'CJK Compatibility Ideographs'; if (code >= 0xFB00 && code <= 0xFB4F) return 'Alphabetic Presentation Forms'; if (code >= 0xFB50 && code <= 0xFDFF) return 'Arabic Presentation Forms-A'; if (code >= 0xFE00 && code <= 0xFE0F) return 'Variation Selectors'; if (code >= 0xFE10 && code <= 0xFE1F) return 'Vertical Forms'; if (code >= 0xFE20 && code <= 0xFE2F) return 'Combining Half Marks'; if (code >= 0xFE30 && code <= 0xFE4F) return 'CJK Compatibility Forms'; if (code >= 0xFE50 && code <= 0xFE6F) return 'Small Form Variants'; if (code >= 0xFE70 && code <= 0xFEFF) return 'Arabic Presentation Forms-B'; if (code >= 0xFF00 && code <= 0xFFEF) return 'Halfwidth and Fullwidth Forms'; if (code >= 0xFFF0 && code <= 0xFFFF) return 'Specials'; if (code >= 0x10000 && code <= 0x1007F) return 'Linear B Syllabary'; if (code >= 0x10080 && code <= 0x100FF) return 'Linear B Ideograms'; if (code >= 0x10100 && code <= 0x1013F) return 'Aegean Numbers'; if (code >= 0x10140 && code <= 0x1018F) return 'Ancient Greek Numbers'; if (code >= 0x10190 && code <= 0x101CF) return 'Ancient Symbols'; if (code >= 0x101D0 && code <= 0x101FF) return 'Phaistos Disc'; if (code >= 0x10280 && code <= 0x1029F) return 'Lycian'; if (code >= 0x102A0 && code <= 0x102DF) return 'Carian'; if (code >= 0x102E0 && code <= 0x102FF) return 'Coptic Epact Numbers'; if (code >= 0x10300 && code <= 0x1032F) return 'Old Italic'; if (code >= 0x10330 && code <= 0x1034F) return 'Gothic'; if (code >= 0x10350 && code <= 0x1037F) return 'Old Permic'; if (code >= 0x10380 && code <= 0x1039F) return 'Ugaritic'; if (code >= 0x103A0 && code <= 0x103DF) return 'Old Persian'; if (code >= 0x10400 && code <= 0x1044F) return 'Deseret'; if (code >= 0x10450 && code <= 0x1047F) return 'Shavian'; if (code >= 0x10480 && code <= 0x104AF) return 'Osmanya'; if (code >= 0x104B0 && code <= 0x104FF) return 'Osage'; if (code >= 0x10500 && code <= 0x1052F) return 'Elbasan'; if (code >= 0x10530 && code <= 0x1056F) return 'Caucasian Albanian'; if (code >= 0x10600 && code <= 0x1077F) return 'Linear A'; if (code >= 0x10800 && code <= 0x1083F) return 'Cypriot Syllabary'; if (code >= 0x10840 && code <= 0x1085F) return 'Imperial Aramaic'; if (code >= 0x10860 && code <= 0x1087F) return 'Palmyrene'; if (code >= 0x10880 && code <= 0x108AF) return 'Nabataean'; if (code >= 0x108E0 && code <= 0x108FF) return 'Hatran'; if (code >= 0x10900 && code <= 0x1091F) return 'Phoenician'; if (code >= 0x10920 && code <= 0x1093F) return 'Lydian'; if (code >= 0x10980 && code <= 0x1099F) return 'Meroitic Hieroglyphs'; if (code >= 0x109A0 && code <= 0x109FF) return 'Meroitic Cursive'; if (code >= 0x10A00 && code <= 0x10A5F) return 'Kharoshthi'; if (code >= 0x10A60 && code <= 0x10A7F) return 'Old South Arabian'; if (code >= 0x10A80 && code <= 0x10A9F) return 'Old North Arabian'; if (code >= 0x10AC0 && code <= 0x10AFF) return 'Manichaean'; if (code >= 0x10B00 && code <= 0x10B3F) return 'Avestan'; if (code >= 0x10B40 && code <= 0x10B5F) return 'Inscriptional Parthian'; if (code >= 0x10B60 && code <= 0x10B7F) return 'Inscriptional Pahlavi'; if (code >= 0x10B80 && code <= 0x10BAF) return 'Psalter Pahlavi'; if (code >= 0x10C00 && code <= 0x10C4F) return 'Old Turkic'; if (code >= 0x10C80 && code <= 0x10CFF) return 'Old Hungarian'; if (code >= 0x10E60 && code <= 0x10E7F) return 'Rumi Numeral Symbols'; if (code >= 0x11000 && code <= 0x1107F) return 'Brahmi'; if (code >= 0x11080 && code <= 0x110CF) return 'Kaithi'; if (code >= 0x110D0 && code <= 0x110FF) return 'Sora Sompeng'; if (code >= 0x11100 && code <= 0x1114F) return 'Chakma'; if (code >= 0x11150 && code <= 0x1117F) return 'Mahajani'; if (code >= 0x11180 && code <= 0x111DF) return 'Sharada'; if (code >= 0x111E0 && code <= 0x111FF) return 'Sinhala Archaic Numbers'; if (code >= 0x11200 && code <= 0x1124F) return 'Khojki'; if (code >= 0x11280 && code <= 0x112AF) return 'Multani'; if (code >= 0x112B0 && code <= 0x112FF) return 'Khudawadi'; if (code >= 0x11300 && code <= 0x1137F) return 'Grantha'; if (code >= 0x11400 && code <= 0x1147F) return 'Newa'; if (code >= 0x11480 && code <= 0x114DF) return 'Tirhuta'; if (code >= 0x11580 && code <= 0x115FF) return 'Siddham'; if (code >= 0x11600 && code <= 0x1165F) return 'Modi'; if (code >= 0x11660 && code <= 0x1167F) return 'Mongolian Supplement'; if (code >= 0x11680 && code <= 0x116CF) return 'Takri'; if (code >= 0x11700 && code <= 0x1173F) return 'Ahom'; if (code >= 0x118A0 && code <= 0x118FF) return 'Warang Citi'; if (code >= 0x11AC0 && code <= 0x11AFF) return 'Pau Cin Hau'; if (code >= 0x11C00 && code <= 0x11C6F) return 'Bhaiksuki'; if (code >= 0x11C70 && code <= 0x11CBF) return 'Marchen'; if (code >= 0x12000 && code <= 0x123FF) return 'Cuneiform'; if (code >= 0x12400 && code <= 0x1247F) return 'Cuneiform Numbers and Punctuation'; if (code >= 0x12480 && code <= 0x1254F) return 'Early Dynastic Cuneiform'; if (code >= 0x13000 && code <= 0x1342F) return 'Egyptian Hieroglyphs'; if (code >= 0x14400 && code <= 0x1467F) return 'Anatolian Hieroglyphs'; if (code >= 0x16800 && code <= 0x16A3F) return 'Bamum Supplement'; if (code >= 0x16A40 && code <= 0x16A6F) return 'Mro'; if (code >= 0x16AD0 && code <= 0x16AFF) return 'Bassa Vah'; if (code >= 0x16B00 && code <= 0x16B8F) return 'Pahawh Hmong'; if (code >= 0x16F00 && code <= 0x16F9F) return 'Miao'; if (code >= 0x16FE0 && code <= 0x16FFF) return 'Ideographic Symbols and Punctuation'; if (code >= 0x17000 && code <= 0x187FF) return 'Tangut'; if (code >= 0x18800 && code <= 0x18AFF) return 'Tangut Components'; if (code >= 0x1B000 && code <= 0x1B0FF) return 'Kana Supplement'; if (code >= 0x1BC00 && code <= 0x1BC9F) return 'Duployan'; if (code >= 0x1BCA0 && code <= 0x1BCAF) return 'Shorthand Format Controls'; if (code >= 0x1D000 && code <= 0x1D0FF) return 'Byzantine Musical Symbols'; if (code >= 0x1D100 && code <= 0x1D1FF) return 'Musical Symbols'; if (code >= 0x1D200 && code <= 0x1D24F) return 'Ancient Greek Musical Notation'; if (code >= 0x1D300 && code <= 0x1D35F) return 'Tai Xuan Jing Symbols'; if (code >= 0x1D360 && code <= 0x1D37F) return 'Counting Rod Numerals'; if (code >= 0x1D400 && code <= 0x1D7FF) return 'Mathematical Alphanumeric Symbols'; if (code >= 0x1D800 && code <= 0x1DAAF) return 'Sutton SignWriting'; if (code >= 0x1E000 && code <= 0x1E02F) return 'Glagolitic Supplement'; if (code >= 0x1E800 && code <= 0x1E8DF) return 'Mende Kikakui'; if (code >= 0x1E900 && code <= 0x1E95F) return 'Adlam'; if (code >= 0x1EE00 && code <= 0x1EEFF) return 'Arabic Mathematical Alphabetic Symbols'; if (code >= 0x1F000 && code <= 0x1F02F) return 'Mahjong Tiles'; if (code >= 0x1F030 && code <= 0x1F09F) return 'Domino Tiles'; if (code >= 0x1F0A0 && code <= 0x1F0FF) return 'Playing Cards'; if (code >= 0x1F100 && code <= 0x1F1FF) return 'Enclosed Alphanumeric Supplement'; if (code >= 0x1F200 && code <= 0x1F2FF) return 'Enclosed Ideographic Supplement'; if (code >= 0x1F300 && code <= 0x1F5FF) return 'Miscellaneous Symbols and Pictographs'; if (code >= 0x1F600 && code <= 0x1F64F) return 'Emoticons'; if (code >= 0x1F650 && code <= 0x1F67F) return 'Ornamental Dingbats'; if (code >= 0x1F680 && code <= 0x1F6FF) return 'Transport and Map Symbols'; if (code >= 0x1F700 && code <= 0x1F77F) return 'Alchemical Symbols'; if (code >= 0x1F780 && code <= 0x1F7FF) return 'Geometric Shapes Extended'; if (code >= 0x1F800 && code <= 0x1F8FF) return 'Supplemental Arrows-C'; if (code >= 0x1F900 && code <= 0x1F9FF) return 'Supplemental Symbols and Pictographs'; if (code >= 0x20000 && code <= 0x2A6DF) return 'CJK Unified Ideographs Extension B'; if (code >= 0x2A700 && code <= 0x2B73F) return 'CJK Unified Ideographs Extension C'; if (code >= 0x2B740 && code <= 0x2B81F) return 'CJK Unified Ideographs Extension D'; if (code >= 0x2B820 && code <= 0x2CEAF) return 'CJK Unified Ideographs Extension E'; if (code >= 0x2F800 && code <= 0x2FA1F) return 'CJK Compatibility Ideographs Supplement'; if (code >= 0xE0000 && code <= 0xE007F) return 'Tags'; if (code >= 0xE0100 && code <= 0xE01EF) return 'Variation Selectors Supplement'; if (code >= 0xF0000 && code <= 0xFFFFF) return 'Supplementary Private Use Area-A'; if (code >= 0x100000 && code <= 0x10FFFF) return 'Supplementary Private Use Area-B'; }