【问题标题】:Regex to match emojis that can be validly combined with skin tone modifiers?正则表达式匹配可以与肤色修饰符有效结合的表情符号?
【发布时间】:2022-06-23 20:47:21
【问题描述】:

检测表情符号(通常意义上的“表情符号”)的JS代码很简单:

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

是否有一些同等简单的方法来检测可以有效添加肤色修饰符的表情符号?

一个关键要求是,随着越来越多的表情符号被添加,或者现有的表情符号变得可以肤色,多年来我不必更新正则表达式。基本上我想知道是否有类似Skin Unicode 属性转义的东西,或者其他一些优雅且面向未来的解决方案。


注意事项:

  • 它必须在没有 DOM 访问的情况下工作(即服务器端、worker 等)。
  • 请注意,目标不是检测肤色修饰符,而是检测可以有效添加肤色修饰符的表情符号 - 例如。正则表达式/函数应匹配????(没有肤色修饰符,但添加一个有效)。
  • 我想强调的是,一个大而老的 unicode-ranges 正则表达式不是面向未来的不符合我的特定用例的要求。但请注意,一堆 Unicode 范围确实符合要求如果它是未来的证明。
  • This question 在考虑标题时似乎很相似,但在阅读问题的主体时,它提出了一个不同的问题。

【问题讨论】:

标签: javascript unicode unicode-escapes


【解决方案1】:

相关的 Unicode 字符属性称为Emoji_Modifier_Base/\p{Emoji_Modifier_Base}/u.test() 将为每个可以使用肤色修饰符的表情符号返回 true。

【讨论】:

  • 哇,谢谢!!我真的很期待这个,但没想到。考虑到它似乎专门针对皮肤修饰符,它的名字很奇怪 - 或者这个角色属性可能包括未来的非肤色修饰?也就是说,它目前与 Chrome 中的猫(IIUC 可以与黑色方块进行 ZWJ-ed 以获得黑猫)不匹配,所以也许它实际上特定于肤色?我认为this 是相关部分?对于像我这样不熟悉 Unicode 深度的人来说,这有点密集。
  • 正确,“表情符号修饰符”一词——尽管听起来很笼统——适用于类人表情符号的五个肤色修饰符。像黑猫这样的表情符号,内部由一只猫和一个黑色方块组成,与之完全分开。这些被称为零宽度连接器 (ZWJ) 序列,它们可以包含您想要的任何表情符号,以任何顺序和任何数量。只有特定的 ZWJ 序列列表被认为是推荐用于通用交换 (RGI) 并且有望跨平台工作,但理论上您可以根据自己的喜好构建自己的新颖序列。
【解决方案2】:

您可以使用Fitzpatrick scale 检测肤色表情符号。带有肤色的表情符号将包含六个 Fitzpatrick 尺度 unicode 中的任何一个。

编辑:

此解决方案使用 Element.getBoundingClientRect() 来确定连接 Fitzpatrick 肤色表情符号后表情符号是否具有相同的宽度和高度。

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

【讨论】:

  • 感谢您的尝试,但除非我弄错了,否则这会回答一个不同的问题——即如何检测肤色修饰符。这个问题实际上是在询问如何检测可以与肤色修饰符有效结合的表情符号。例如,一个正确的函数/正则表达式应该匹配?,因为它可以有效地添加一个肤色修饰符。我将在“注释”部分添加另一点来强调这一点。
  • 啊,是的,我的错。我将在代码中进行调整
  • 好了,我已经更新了解决方案。你现在可以调用函数 isEmojiSkinToneAdaptable(emoji) ,它会给你一个布尔评估给定的表情符号是否可以有肤色
  • @BruntoT,重新编辑您的答案,在我的情况下,我需要它在没有 DOM 访问(Node.js 和 Deno)的情况下也能工作,但这是一个好主意!我相信这对需要纯客户端解决方案的访问此页面的人会有所帮助,所以我 +1 ?
  • 酷。问题在于,可以应用的表情符号和不能应用肤色的表情符号之间并没有真正的普遍区别,因为它们都是基于 unicode 范围的。如果您不想要在给定范围/数组内寻找特定表情符号的大型正则表达式,您可能不会有任何运气来找到解决方案。不过祝你好运,你在这个帖子上提出的问题绝对很有趣:)
猜你喜欢
  • 2018-06-05
  • 2013-01-09
  • 2019-11-02
  • 1970-01-01
  • 1970-01-01
  • 2018-12-21
  • 2016-07-19
  • 1970-01-01
  • 2012-01-11
相关资源
最近更新 更多