我发现了一个很棒的方法来检测表情符号,使用正则表达式,不使用“巨大的魔法范围”,使用Unicode property escape:
console.log(/\p{Emoji}/u.test('flowers 🌼🌺🌸')) // true
console.log(/\p{Emoji}/u.test('flowers')) // false
但是当我分享这个知识in this answer时,@Bronzdragon注意到\p{Emoji}
也匹配数字!为什么会这样?数字不是emoji吗?
console.log(/\p{Emoji}/u.test('flowers 123')) // unexpectdly true
// regex-only workaround by @Bonzdragon
const regex = /(?=\p{Emoji})(?!\p{Number})/u;
console.log(
regex.test('flowers'), // false, as expected
regex.test('flowers 123'), // false, as expected
regex.test('flowers 123 🌼🌺🌸'), // true, as expected
regex.test('flowers 🌼🌺🌸'), // true, as expected
)
// more readable workaround
const hasEmoji = str => {
const nbEmojiOrNumber = (str.match(/\p{Emoji}/gu) || []).length;
const nbNumber = (str.match(/\p{Number}/gu) || []).length;
return nbEmojiOrNumber > nbNumber;
}
console.log(
hasEmoji('flowers'), // false, as expected
hasEmoji('flowers 123'), // false, as expected
hasEmoji('flowers 123 🌼🌺🌸'), // true, as expected
hasEmoji('flowers 🌼🌺🌸'), // true, as expected
)
2条答案
按热度按时间ovfsdjhp1#
根据这篇文章,digtis,
#
,*
,ZWJ和其他一些字符包含Emoji
属性设置为 Yes,这意味着数字被认为是有效的emoji字符:例如,
1
是一个数字,但当它与U+FE0F
和U+20E3
字符组合时,它就变成了一个emoji:1️:如果你想避免匹配数字,使用
Extended_Pictographic
Unicode category class:Extended_Pictographic字符包含除一些Emoji_Components之外的所有Emoji字符。
因此,您可以使用
/\p{Extended_Pictographic}/gu
来测试大多数emoji,或者使用/\p{Extended_Pictographic}/u
来测试单个emoji,或者使用/[\p{Extended_Pictographic}\u{1F3FB}-\u{1F3FF}\u{1F9B0}-\u{1F9B3}]/u
来匹配emoji以及浅色皮肤到深色皮肤模式的字符和红发到白发的字符:a11xaf1n2#
使用
\p{Emoji}
的问题之一是Unicode将Emoji
定义为 * 字符属性 *,这意味着它只捕获单个字符或代码点。因此,\p{Emoji}
似乎可以解决你的问题,只要你只对单码点表情符号(如🫱(U+1FAF1))进行测试,但这是误导。然而,Unicode定义的绝大多数emoji由多个代码点组成,因此无法与
\p{Emoji}
匹配。例如:(🫱🏿🫲🏻U+1FAF1U +1F3FF U+200D U+1FAF2U +1F3FB)。幸运的是,Unicode定义了几个字符串的属性,你猜到了,它们并不局限于一个代码点。名为
RGI_Emoji
的字符串属性包含了所有官方推荐用于通用交换的表情符号,并且很可能是你真正想要的,而不是Emoji
。在JavaScript正则表达式中,启用the
v
flag时可以使用字符串的属性。