【发布时间】:2020-03-15 10:48:37
【问题描述】:
问题很简单:我有一个字符串
str,我如何检查str是否是一个表情符号,而不是别的?此外,我不希望使用其他库。匹配
"????"、"⛹????♂️"、"3️⃣",但不匹配"????a"、"????"、"????????"
我无法找到解决方案,但到目前为止我已经尝试过以下一些方法:
尝试的解决方案 1 - 玩转长度和 ... 运算符
我了解到 emojis 占用超过 1 个字节,有些甚至占用 4 个字节,甚至更多...我们可以通过字符串的 length 属性来衡量:
console.log("????".length); // 2
console.log("????️".length); // 3
console.log("⛹????♂️".length); // 6
然后我发现... 运算符将这一点考虑在内并正确分隔数组中的表情符号 - 然后我可以看到结果数组的length 属性并检测它们是否不同。
str = "⛹????♂️";
if (str.length !== [...str].length) {
// is emoji?
} else {
// is not emoji
}
但这不会检查其他多字节字符,例如长度为 2 的 ????。此外,一些表情符号仍然会以奇怪的方式分开。
尝试的解决方案 2 - 正则表达式、正则表达式
当然,正则表达式值得研究,但我还没有找到可行的解决方案。
This answer 的正则表达式\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff] 可以很好地检测字符串是否有任何表情符号,但应用于我的情况会产生很多问题。这是我的测试:
A 部分 - 没有字符串正则表达式的开始/结束(^ 和 $)
-
2A.1
str.match(regex)非常不一致,它分解了一些表情符号和其他一些无法使用的符号。我没有办法确定它是否包含非表情符号字符,或者它是否包含多个表情符号:
let regex = /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/;
console.log("5️⃣".match(regex)); // [ '⃣', '⃣', index: 2, input: '5️⃣' ]
console.log("????".match(regex)); // [ '????', '????', index: 0, input: '????' ]
console.log("????️????️".match(regex)); // [ '????', '????', index: 0, input: '????️????️' ]
console.log("a⛅".match(regex)); // [ '⛅', '⛅', index: 1, input: 'a⛅' ]
-
2A.2 只要字符串中包含表情符号,
regex.test(str)就会返回 true,这不是我要寻找的行为:
let regex = /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/;
console.log(regex.test("5️⃣")); // true - correct
console.log(regex.test("a")); // false - correct
console.log(regex.test("????️????️")); // true - should be false
console.log(regex.test("hello ⛅!")); // true - should be false
B 部分 - 字符串正则表达式的开始/结束(^ 和 $)
-
2B.1
str.match(regex)出于某种原因在某些表情符号上返回null。我不知道为什么,但我假设它与为什么str.match(regex)会在 A 部分中分解这些表情符号有某种关系:
let regex = /^(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])$/;
console.log("5️⃣".match(regex)); // null
console.log("????".match(regex)); // [ '????', '????', index: 0, input: '????' ]
console.log("????️".match(regex)); // null
console.log("⛅".match(regex)); // [ '⛅', '⛅', index: 1, input: 'a⛅' ]
console.log("????????".match(regex)); // null
-
2B.2
regex.test(str)将在相同的表情符号上返回false,而在str.match(regex)上返回null:
let regex = /^(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])$/;
console.log(regex.test("5️⃣")); // false - should be true
console.log(regex.test("????")); // true - correct
console.log(regex.test("????️")); // false - should be true
console.log(regex.test("⛅")); // true - correct
console.log(regex.test("????????")); // false - correct
C 部分 - 其他正则表达式
- 我找到了this one,但它给出了类似的不一致,虽然不一样
/(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c[\ude01\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c[\ude32\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|[\ud83c[\ude50\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g:
let regex = /^(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c[\ude01\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c[\ude32\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|[\ud83c[\ude50\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])$/g
console.log(regex.test("5️⃣")); // true - correct
console.log(regex.test("????")); // false - should be true
console.log(regex.test("????️")); // false - should be true
console.log(regex.test("⛅")); // true - correct
console.log(regex.test("????????")); // false - correct
- 这也很糟糕(第二次测试根据第一次测试改变?)
let regex = /^(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c[\ude01\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c[\ude32\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|[\ud83c[\ude50\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])$/g
console.log(regex.test("⛹????♂️")); // false
console.log(regex.test("⛅")); // true
let regex = /^(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c[\ude01\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c[\ude32\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|[\ud83c[\ude50\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])$/g;
console.log(regex.test("⛹")); // true
console.log(regex.test("⛅")); // false
有没有办法解决所有这些表情符号/unicode/regex 混乱?库/api是唯一的方法吗?他们是怎么做到的?
【问题讨论】:
-
我个人认为维护一个正则表达式并不是一个好主意,除非你是从unicode specification 生成它。不过,已经有一些图书馆正在这样做。见emoji-regex 和emoji.json。
-
感谢 Wiktor Stribiżew,该正则表达式完美运行!我可以知道你是如何或从哪里得到这个的吗?
-
图书馆有时间和地点。恕我直言,这是其中之一。让其他人为您解决这个非常复杂的问题似乎远远超过了维护依赖项及其版本和文件大小的成本。
-
回复:“他们是如何做到的” Daniel Vickers 链接的库指的是:unicode.org/reports/tr29/#Default_Grapheme_Cluster_Table
标签: javascript node.js regex unicode emoji