Pertanyaannya sederhana: Saya punya string
str
, bagaimana cara memeriksa apakahstr
ada satu emoji tunggal, dan tidak ada yang lain? Selain itu saya lebih suka tidak menggunakan perpustakaan lain.Pertandingan
"π"
,"βΉπΏββοΈ"
,"3οΈβ£"
tapi tidak"πa"
,"π"
,"ππ"
Saya mengalami masalah dalam menemukan solusi tetapi berikut adalah beberapa hal yang saya coba sejauh ini:
Solusi yang Dicoba 1 - Mainkan panjang dan ...
operator
Saya belajar bahwa emoji menempati lebih dari satu byte, beberapa bahkan menempati 4 byte, atau lebih ... dan kita dapat mengukurnya melalui length
properti string :
console.log("π".length); // 2
console.log("π‘οΈ".length); // 3
console.log("βΉπΏββοΈ".length); // 6
Kemudian saya mengetahui bahwa ...
operator memperhitungkannya dan memisahkan emoji dengan benar dalam array - Saya kemudian dapat melihat length
properti array yang dihasilkan dan mendeteksi apakah mereka berbeda.
str = "βΉπΏββοΈ";
if (str.length !== [...str].length) {
// is emoji?
} else {
// is not emoji
}
Tapi ini tidak memeriksa untuk karakter multi-byte lainnya seperti π‘
yang panjangnya 2. Ditambah beberapa emoji masih terpisah secara aneh.
Attempted Solution 2 - Regex, ekspresi reguler
Tentu saja regex akan menjadi hal yang perlu diperhatikan tetapi saya belum menemukan solusi yang layak.
Regex jawaban ini\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff]
berfungsi dengan baik untuk mendeteksi jika suatu string memiliki emoji, tetapi diterapkan pada situasi saya menghasilkan banyak masalah. Inilah tes saya:
Bagian A - Tanpa awal / akhir string regex ( ^
dan $
)
- 2A.1
str.match(regex)
sangat tidak konsisten, itu memecah beberapa emoji dan beberapa lainnya tidak dapat digunakan. Saya tidak melihat cara untuk mengetahui apakah itu bahkan mengandung karakter non-emoji atau jika mengandung lebih dari satu emoji:
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)
mengembalikan true setiap kali emoji termasuk dalam string, yang bukan perilaku yang saya cari:
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
Bagian B - Dengan awal / akhir string regex ( ^
dan $
)
- 2B.1
str.match(regex)
mengembalikannull
emoji tertentu karena suatu alasan. Saya tidak tahu mengapa, tetapi saya berasumsi ada kaitannya dengan mengapastr.match(regex)
akan memecah emoji ini di Bagian 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)
akan kembalifalse
pada emoji yang sama di mana ia akan kembalinull
padastr.match(regex)
:
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
Bagian C - Ekspresi reguler lainnya
- Saya menemukan ini tetapi memberikan inkonsistensi yang serupa, meskipun tidak sama
/(?:[\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
- Juga ini rusak parah (perubahan tes kedua berdasarkan tes pertama?)
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
Apakah ada cara untuk mengatasi semua kekacauan emoji / unicode / regex ini? Apakah perpustakaan / apis satu-satunya cara? Bagaimana mereka melakukannya?
Jawaban:
Menggunakan perpustakaan ini: https://github.com/foliojs/grapheme-breaker coba ini:
dan panjangnya harus kembali 1.
sumber
Emoji ditentukan dalam UAX # 51. Properti
\p{Emoji}
harus bekerja, tetapi tidak.Lakukan dengan cara yang sulit. Parse
emoji-*.txt
:Ini memberi kita daftar emoji yang dipisahkan baris baru. Menggunakan Regexp :: Assemble :: Compressed, hasilnya adalah
sumber