Emoji.prototype.length-Unicodeの感情記号に関するストーリー

Habrは絵文字に対してかなり敵対的です(ここには表示されません)。「パドンカフ語」のような言語であると考えています。 深刻な人向けではありません。 結局のところ、それらは両方ともほぼ同時に登場しました。 そして、「アルバニア人」のyazygがすぐに忘却に陥った場合、絵文字は単純なセミコロンとブラケットから完全なUnicode文字に進化しました。 この記事の著者は、これらの小さなエンティティが「内部」にあるものに注目することを提案しています(以下、イタリック体は翻訳者のメモです)。



EmojiFamilyHeader

Stefan JudisTwitterGitHub )によるContentful向けのオリジナル記事



絵文字は、今日のテキスト通信の基礎です。 これらの小さなキャラクターがいなければ、今日のチャットでの会話の多くは、気まずい沈黙や誤解を招いていたでしょう。 SMSがクールなものだった古き良き時代を今でも覚えています。



絵文字なしでチャットするという提案は、「冗談は何ですか?」というメッセージにつながる可能性があります。 誰もがすぐに、ユーモアと皮肉(ちなみに、皮肉を少なくすることは私たちを傷つけないだろう)が、書かれたサインだけを使用して伝えるのは容易ではないことに気づいた。 ある時点で、最初の絵文字が登場し、すぐにテキスト形式の会話の基本的なコンポーネントの1つになりました。



私は毎日絵文字を使用していますが、どのように機能するのか疑問に思いません。 明らかに、それらは何らかの形でUnicodeに接続されていますが、内部で何が起こっているのかわかりませんでした。 そして正直に気にしませんでした。



Wes Bos からツイートに出会ったとき、すべてが変わりました。彼は絵文字ファミリーを含む行でいくつかのJavaScript操作を示しました。



[...'👨‍👩‍👦'] // ["👨", "", "👩", "", "👦"]
‘👨‍👩‍👦’.length // 8
view raw emoji-code-01.js hosted with ❤ by GitHub


このような行でスプレッド演算子を使用してそれほど驚かないと思いますが、1つの目に見える文字が3つの文字と2つの空の行に分割されているという事実に少し戸惑っています。 また、 length



文字列のプロパティが値8を返したという事実は、スプレッド演算子が返した配列には5つの値がありましたが、8ではなかったため、さらに驚かされました。



考え直すことなく、コンソールを開いて、すべてがWeightで説明されているとおりに発生するようにしました。 ここで何が起こっているのでしょうか? 私は、Unicode、JavaScript、および絵文字ファミリーをさらに深く掘り下げて、それを理解することにしました。



救助のためのユニコード



JavaScriptがこのように絵文字を処理する理由を理解するには、Unicode自体を詳しく調べる必要があります。



Unicodeは、IT業界における文字エンコーディングの国際標準です。 各文字、記号、または記号と数値の間の対応を確立します。 Unicodeのおかげで、たとえば、特別なドイツ語の文字( umlauts )ß、ä、öを含むドキュメントを、システムがそれらを使用しない人々と共有できます。 Unicodeのおかげで、エンコーディングはさまざまなプラットフォームと環境で機能します。



Unicodeは1,114,112の異なる文字を定義し、通常はU+



続けて16進表記の数字を使用して表されます 。 Unicode文字の範囲はU+0000



で始まり、 U+10FFFF



終わります。



コードスペース全体(100万文字以上)は17トンに分割されます。 「プレーン」、および各プレーンには65,000を超える文字が含まれます。 最も重要なのはゼロ、つまり「基本的な多言語面」(BMP)です。 範囲はU+0000



からU+FFFF



です。



ベースプレーンには、ほとんどすべての現代言語の文字に加えて、多数の他の文字が含まれています。 残りの16個のプレーンはオプションと呼ばれ、ほとんどの絵文字の定義など、さまざまな目的に使用されます。



絵文字はどのように定義されますか?



知っているように、絵文字は少なくとも1つのUnicode文字で定義されます。 絵文字の完全なリストに表示されているすべての絵文字を見ると、それらの多くがあることがわかります。 「たくさん」という言葉は、本当にたくさんのことを意味します。 今日、Unicodeで何種類の絵文字が定義されているのか自問するかもしれません。 ITでよくあるように、この質問に対する答えは「それは…に依存します」であり、答えを得る前にこれに対処しなければなりません。



上で書いたように、絵文字は少なくとも 1人のキャラクターによって定義さます。 これは、他のいくつかの絵文字とキャラクターの組み合わせによって定義される絵文字があることを意味します。 これらの組み合わせはシーケンスと呼ばれます。 シーケンスのおかげで、ニュートラルな絵文字(通常は黄色の肌色で表示)を変更して、より個人的なものにすることができます。



さまざまな肌の色のシーケンス修飾子



チャットで、親指のアイコンを肌の色に合うように変更できることに気付いた瞬間を今でも覚えています。 それは私に所有感を与え、この親指は以前のすべての投稿よりも私に近いと感じました。



Unicodeには、ニュートラルな絵文字を変更したり、人間の肌の色をさまざまに表現したりするための5つの修飾子があります。 修飾子の範囲はU+1F3FB



U+1F3FF



、フィッツパトリックスケールに基づいてます。



これらの修飾子を使用して、ニュートラルな絵文字を同じに、ただし肌の色を変えることができます。 例を見てみましょう:



// U+1F467 + U+1F3FD
// 👧 + 🏽
> 👧🏽
view raw emoji-code-02.js hosted with ❤ by GitHub


シンボルがU+1F467



である絵文字の女の子をU+1F467



し、スキンカラーモディファイU+1F3FD



U+1F3FD



)を適用すると、このシーケンスをサポートするシステムでこのスキンカラーの女の子が自動的に受信されました。



さらに多様なZWJシーケンス



肌の色だけが人を区別するものではありません。 家族の例を思い出すと、すべての家族が男性、女性、少年で構成されているわけではないことが明らかになります。



Unicodeには、普通の家族( U+1F46A



絵文字ファミリー )、しかしすべての家族がそのように見えるわけではありません。 いわゆるゼロ幅ジョイナー(ZWJ)シーケンスを使用して、任意のファミリを作成できます。



ゼロ幅コンバイナー( U+200D



)と呼ばれる特別なシンボルがあり、このシンボルは接着剤のように機能し、2つのシンボルを可能な限り1つ表示する必要があることを示します。



論理的に考えると、家族に見せるために何を接着することができますか? 答えは簡単です-大人2人と子供1人。 ZWJシーケンスを使用すると、さまざまなファミリを簡単にマッピングできます。



//
// U+1F46A
> 👪
// ZWJ-: (, , )
// U+1F468 + U+200D + U+1F469 + U+200D + U+1F466
// 👨‍ + U+200D + 👩‍ + U+200D + 👦
> ‍👨‍👩‍👦
// ZWJ-: (, , )
// U+1F469 + U+200D + U+1F469 + U+200D + U+1F467
// 👩‍ + U+200D + 👩‍ U+200D + 👧
> ‍👩‍👩‍👧
// ZWJ-: (, , , )
// U+1F469 + U+200D + U+1F469 + U+200D + U+1F467 + U+200D + U+1F467
// 👩‍ + U+200D + 👩‍ + U+200D + 👧‍ + U+200D + 👧
> ‍👩‍👩‍👧‍👧
view raw emoji-code-03.js hosted with ❤ by GitHub


すべての可能なシーケンスのリストを見ると、たとえば、父親が1人、女の子が2人いるなど、さらに多くのオプションがあることがわかります。 残念ながら、このドキュメントの執筆時点では、これらのシーケンスのサポートはあまり良くありませんが、ZWJシーケンスは徐々に劣化しグレースフル劣化 )、個々の絵文字のシーケンスを返します。 これにより、セマンティクスを維持できます。



// ZWJ-: (, , )
// U+1F468 + U+200D + U+1F467 + U+200D + U+1F467
// 👨‍ + U+200D + 👧 + U+200D + 👧
> ‍👨‍👧‍👧 //
view raw emoji-code-04.js hosted with ❤ by GitHub


別のクールなことは、統一の原則が絵文字ファミリーだけでなく適用されることです。 たとえば、有名なデビッドボウイ絵文字(本名は「歌手」)を取り上げてみましょう。 これは、男性( U+1F468



)、ZWJコンバイナー、およびマイク( U+1F3A4



)で構成されるZWJシーケンスでもあります。

画像

そして、ごU+1F468



、男性( U+1F468



)を女性( U+1F469



)にU+1F469



、歌手(または女性版のDavid Bowie)が得られます。 また、肌の色の修飾子を追加して、黒の歌手を得ることもできます。 クラス!



// ZWJ-: -
// U+1F469 + U+1F3FF + U+200D + U+1F3A4
// 👩 + 🏿 + U+200D + 🎤
> 👩🏿🎤 //
view raw emoji-code-05.js hosted with ❤ by GitHub


残念ながら、執筆時点では、これらの新しいキャラクターのサポートも望まれていません。



絵文字の量が異なる



そのため、今日どのくらいの絵文字が存在するかという質問に対する答えは、絵文字をどう考えるかによって異なります。 これは絵文字の表示に使用された文字数ですか? または、表示できるすべての絵文字オプションを検討しますか?



表示できる絵文字のすべてのバリアント(シーケンスとバリエーションを含む)をカウントすると、 2,198が得られます。カウントのプロセスに興味がある場合は unicode.orgでそれに関するセクション全体紹介します。



また、「カウント方法」の質問に、新しい絵文字とUnicode文字が常に仕様に追加されるという事実を追加できます。これにより、正確な数の追跡がさらに困難になります。



JavaScriptおよび16ビットエンコーディングの文字列に戻る



JavaScriptで使用される文字列形式であるUTF-16では、ほとんどの文字を表すために単一の16ビットコード値(2バイト)が使用されます。 これは、65,000を超える異なるコード値が1つのJavaScript文字に収まることを意味します。 これは、Basic Multilingual Plane(BMP)とまったく同じです。 それでは、Unicode文字をBMPで定義された複数の文字に一致させてみましょう。



‘ツ’.length // 1 -> U+FF82
‘⛷’.length // 1 -> U+26F7
‘☃’.length // 1 -> U+9731
view raw emoji-code-06.js hosted with ❤ by GitHub


これらの行にlength



プロパティを適用すると、ユニットが得られますが、これは期待どおりです。 しかし、BMPの範囲外の文字をJavaScriptで使用したい場合はどうなりますか?



代理カップルが急いで救助に行く



ベースプレーンで定義された2つのキャラクターを組み合わせて、その外側にある別のキャラクターを表示できます。 この組み合わせは、サロゲートペアと呼ばれます。



U+D800



からU+DBFF



の範囲にあるシンボルは、いわゆるシニアまたは「リーディング」サロゲート用に予約されており、 U+DC00



からU+DFFF



の範囲にあるシンボルはジュニアまたは「クローズ」サロゲート用です。



これらの2つの文字は、常に最も古いものから始まり、若いサロゲートで終わるペアで使用する必要があります。 次に、範囲外の文字をデコードするための特別な式が適用されます。



例を見てみましょう:



‘👨’.length // 2
‘👨’.charCodeAt(0) // 55357 -> U+D83D -
‘👨’.charCodeAt(1) // 56424 -> U+DC68
‘👨’.codePointAt(0) // 128104 -> U+1F468 -
‘👨’.codePointAt(1) // 56424 -> U+DC68
view raw emoji-code-07.js hosted with ❤ by GitHub


絵文字の普通の人は、記号U+1F468



表されます。 この文字は、単一の16ビットJavaScript文字で表すことはできません。 したがって、BMPの外側の1文字( U+1F468



)を表示するには、BMPに含まれる2文字( U+D83D



およびU+DC68



)で構成されるサロゲートペアを使用する必要があります。



JavaScriptで文字を分析するには、2つの方法があります。 charCodeAt



を使用できます。これは、共通文字を構成するために使用される場合、「代理」疑似文字のコードを返します。 2番目のメソッドはcodePointAt



。これは、「先頭」の代理文字を「ヒット」した場合、サロゲート文字の結合ペアのコードを返し、「ヒット」した場合、「閉じ」代理文字のコードを返します。



これは非常に紛らわしいと思いますか? 私もそう思うし、これら2つのメソッド( charCodeAtcodePointAt )に関するMDNの記事を注意深く読むことを強くお勧めします( learn.javascript.ruで読むこともできます)。



絵文字の男性のシンボルを詳しく見てみましょう。 charCodeAtを使用すると、サロゲートペアで使用される「サロゲート」擬似文字のコードを取得できます。



最初の文字の値は55357で、これは16進表記のD83Dに対応しています。 これは「主要な」擬似文字です。 2番目の値56424はDC68に対応し、「終了」擬似文字です。 これは古典的なサロゲートペアで、式による計算の結果として、絵文字の男性のシンボルに対応する結果128104が得られます。



//
0x1F468 = (0xD83D - 0xD800) * 0x400 + 0xDC68 - 0xDC00 + 0x10000
//
128104 = (55357 - 55296) * 1024 + 56424 - 56320 + 65536<
view raw emoji-code-08.js hosted with ❤ by GitHub


文字数と長さのプロパティ



Unicodeコードと文字を処理したら、 length



プロパティの奇妙な動作に進むことができます。 最初に考えた文字ではなく、Unicodeコード値の数を返すことがわかりました。 これにより、JavaScript文字列でUnicodeを使用するときにエラーをキャッチするのが困難になる可能性があります。したがって、BMP以外の文字を扱う場合は注意してください。



おわりに



重量の例に戻りましょう。それからすべてが始まりました。



// ZWJ-: (, , )
// U+1F468 + U+200D + U+1F469 + U+200D + U+1F466
[...'👨‍👩‍👦'] // ["👨", "‍", "👩", "‍", "👦"]
‘👨‍👩‍👦’.length // 8
//
// U+1F46A
[...’👪’] // [’👪’]
’👪’.length // 2
view raw emoji-code-09.js hosted with ❤ by GitHub


ここに表示されている絵文字ファミリーは、男性、女性、および男の子で構成されています。 spreadステートメントは、個々の絵文字を返します。 空の行は実際には空ではありません-それらはZWJコンバイナです。 この場合、 length



プロパティは絵文字ごとに2を返し、ZWJコンバイナに対して1を返します。 その結果、8が得られます。



Unicodeに没頭するのは本当に楽しかったです。 このトピックにも興味がある場合は、 @ fakeunicode Twitterアカウントをお勧めします。 Unicodeの機能に関する興味深い情報がたくさんあります。 ところで、絵文字に関するポッドキャスト会議もあることをご存知でしたか? 私は、私たちがいたるところで使用しているこれらの小さなシンボルについてもっと学ぶことは非常に興味深いので、これすべてを続けます。 おそらく、このトピックに興味があります。



All Articles