3

The JS code to detect emojis (in the usual sense of the term "emoji") is simply:

let str = "...";
if(/\p{Extended_Pictographic}/u.test(str)) {
  // do something
}

Is there some equivalently simple way to detect emojis that can have skin tone modifiers validly added to them?

A key requirement is that I don't have to update the regex over the years as more emojis are added, or existing emojis become skin-tone-able. Basically I'm wondering if there's something like a Skin Unicode property escape, or some other elegant and future-proof solution.


Notes:

  • It must work without DOM access (i.e. server-side, workers, etc.).
  • Note that the goal is not to detect skin tone modifiers, but to detect emojis that can validly have a skin tone modifier added to it - e.g. the regex/function should match (doesn't have skin tone modifier, but it is valid to add one to it).
  • I want to emphasise that a big-old-bunch-of-unicode-ranges regex that's not future-proof does not fit the requirements of my particular use case. But note that a bunch of Unicode ranges does fit the requirements if it's future proof.
  • This question appears to be similar when considering the title, but upon reading the body of the question, it's asking a different question.
joe
  • 3,752
  • 1
  • 32
  • 41
  • Thus the OP is looking for a solution which proves the coverage of something like ... [thumbs up default](https://unicode.org/emoji/charts/full-emoji-list.html#1f44d) and its [skin tone combinations](https://unicode.org/emoji/charts-13.1/full-emoji-modifiers.html#1f44d_1f3fb) ..? – Peter Seliger Apr 17 '22 at 11:46
  • 1
    Hi @PeterSeliger, the goal is to detect emojis like , , , etc. which can validly have skin tone modifiers added to them (in a *future-proof* manner, given that more emojis can be added, and the spec could perhaps be adjusted to allow existing emojis to have skin tone variations). – joe Apr 17 '22 at 11:53
  • https://emojipedia.org/emoji-sequence/ – JosefZ Apr 17 '22 at 12:00
  • https://github.com/mathiasbynens/emoji-regex – JosefZ Apr 17 '22 at 18:23

2 Answers2

3

The relevant Unicode character property is called Emoji_Modifier_Base. /\p{Emoji_Modifier_Base}/u.test() will return true for every emoji character that can take a skin tone modifier.

CharlotteBuff
  • 3,389
  • 1
  • 16
  • 18
  • Wow, thank you!! I was really hoping for this, but not expecting it. It's weirdly named considering it seems to be specifically about skin modifiers - or perhaps this character property may include future non-skin-tone modifications? That said, it doesn't currently match the cat (which IIUC can be ZWJ-ed with the black square to get a black cat) in Chrome, so perhaps it *is* actually specific to skin tones? I think [this](https://unicode.org/reports/tr51/#Diversity_Implementations) is the relevant section? It's a bit dense for someone like myself who isn't familiar with the depths of Unicode. – joe Apr 18 '22 at 15:21
  • 1
    Correct, the term “emoji modifier” – despite sounding quite generic – applies *only* to the five skin tone modifiers for human-like emoji. Emoji like the black cat, which consists of a cat and a black square internally, are completely separate from that. These are called Zero Width Joiner (ZWJ) sequences and they can consist of any emoji you want, in any order and in any amount. Only a certain list of ZWJ sequences is considered Recommended for General Interchange (RGI) and is expected to work across platforms, but in theory you can build your own novel sequences to your heart’s content. – CharlotteBuff Apr 18 '22 at 19:27
2

You can use Fitzpatrick scale to detect a skin-toned emoji. An emoji with a skin tone will contain any one of the six Fitzpatrick scale unicodes.

EDIT:

This solution uses Element.getBoundingClientRect() to determine whether an emoji will have the same width and height after having concatenated the Fitzpatrick skin tone emoji.

function isEmojiSkinToneAdaptable(emoji) {
  const SKIN_TONES = [
    '\u{1f3fb}', // skin tone 1 & 2
    '\u{1f3fc}', // skin tone 3
    '\u{1f3fd}', // skin tone 4
    '\u{1f3fe}', // skin tone 5
    '\u{1f3ff}', // skin tone 6
  ];
  
  function getRemovedSkinToneEmoji(emoji) {
    let emojiCopy = ' '.concat(emoji).slice(1);
    SKIN_TONES.forEach(skinTone => {
      emojiCopy = emojiCopy.replace(skinTone, '');
    })
    return emojiCopy;
  }
  
  function getEmojiRects(emoji) {
    let span = document.createElement('span');
    span.style.position = 'fixed';
    span.style.top = '-99999px';
    span.textContent = emoji;
    document.body.append(span);
    let emojiRects = span.getBoundingClientRect();
    span.remove();
    return emojiRects;
  }

  let baseEmoji = getRemovedSkinToneEmoji(emoji);
  let skinToneEmoji = baseEmoji + SKIN_TONES[1];
  
  let baseEmojiRects = getEmojiRects(baseEmoji);
  let skinToneEmojiRects = getEmojiRects(skinToneEmoji);

  return baseEmojiRects.width === skinToneEmojiRects.width 
    && baseEmojiRects.height === skinToneEmojiRects.height;
}

console.log(`Human with skin tone: ${isEmojiSkinToneAdaptable('')}`); // true
console.log(`Thumbs up without skin tone: ${isEmojiSkinToneAdaptable('')}`); // true
console.log(`Animal: ${isEmojiSkinToneAdaptable('')}`); // false
BrunoT
  • 414
  • 4
  • 9
  • 1
    Thanks for your attempt, but unless I'm mistaken this answers a different question - that is, how to detect skin tone modifiers. This question is in fact asking how to detect emojis that can be validly combined with a skin tone modifier. For example, a correct function/regex should match ``, since it can validly have a skin tone modifier added to it. I'll add another point the the "notes" section to emphasise this. – joe Apr 17 '22 at 11:42
  • Ahh yes, my bad. I will make tweaks in the code – BrunoT Apr 17 '22 at 11:45
  • There you go, I've updated the solution. You can now call the function isEmojiSkinToneAdaptable(emoji) and it will give you a boolean evaluation of whether the given emoji can or can not have a skin tone – BrunoT Apr 17 '22 at 13:46
  • @BruntoT, RE your edited answer, in my case I need it to also work without DOM access (Node.js and Deno), but this is a neat idea! I'm sure it will be helpful for people who hit this page in need a purely client-side solution, so +1 from me – joe Apr 17 '22 at 13:53
  • Cool. The problem is that there isn't really a general difference between emojis that can and emojis that can not have a skin tone applied since they're all unicode-range based. If you don't want large regexes which look for specific emojis within a given range/array you probably wont be getting any luck of finding the solution. Nevertheless good luck, the question you asked on this thread is definitely interesting :) – BrunoT Apr 17 '22 at 13:59
  • Yeah, for that reason I was hoping that there was a Unicode property escape, or something in the spec that said "all new skin emojis will ". I'm going to clarify in the question that it's okay if it's a bunch of ranges, so long as it's future proof. But it does sound like I'll have to wait for a Unicode property escape to get a proper solution here Thanks for your help! – joe Apr 17 '22 at 16:57