EmoArt
投稿する
ブログ

絵文字の文字数の数え方 - SNS の文字制限で損しないために

最終更新: 2026-05-24·約 5 分

この記事は約 5 分で読めます。

「あれ、絵文字を 5 個入れただけで 30 文字使ってる?」その違和感には、Unicode の構造的な理由があります。絵文字は見た目では 1 文字でも、システム内部では 2〜10 個以上のコードポイントで構成されることが普通です。 プラットフォームごとに「何を 1 文字と数えるか」のルールも異なり、同じ絵文字が Twitter では 2 文字、 別のシステムでは 1 文字として扱われたりします。この記事では、その仕組みと実用的な対処法を解説します。

そもそも「文字」とは何か

絵文字の文字数を語る前に、コンピュータ上の「文字」には複数のレイヤーがあることを押さえる必要があります。

  • コードポイント: Unicode が割り当てる番号 1 つ。例: 「あ」は U+3042 で 1 コードポイント。
  • コードユニット: 文字エンコーディングが扱う最小単位。UTF-16 では 16 ビット (2 バイト)。
  • 書記素クラスタ (grapheme cluster): 人間が「1 文字」と認識する単位。複数のコードポイントから構成されることがある。

絵文字の文字数問題は、この 3 つのレイヤーが食い違うことから生まれます。 プラットフォームによって、どのレイヤーで数えるかが違うのです。

サロゲートペア - 絵文字が 2 文字になる理由

Unicode のコードポイントは U+0000 から U+10FFFF まで定義されており、これを表現するには 21 ビット必要です。 しかし JavaScript の文字列、Java、C# など多くの言語が内部で採用している UTF-16 は、 基本的に 16 ビット (1 コードユニット) で文字を表現する設計です。

16 ビットでは U+FFFF までしか表現できないため、それを超えるコードポイント (絵文字の大半が該当) は、 2 つのコードユニットを組み合わせる「サロゲートペア」で表現します。 つまり、絵文字 1 つを "🌸".length で数えると、JavaScript では 2 が返ります。

"🌸".length          // → 2 (サロゲートペア)
"あ".length          // → 1 (BMP 範囲内)
[..."🌸"].length     // → 1 (コードポイント単位の分解)

この差は、Web フォームの文字数バリデーションで「絵文字を入れたら制限を超える」現象の主犯です。 単純に .length で実装している UI は、絵文字利用者を実質的に不利にしています。

ZWJ シーケンス - 1 つの絵文字が 5〜10 コードポイント

家族絵文字や職業絵文字は、複数の絵文字を Zero Width Joiner (U+200D) でつないで 1 つの絵文字に見せる仕組みです。

  • 👨‍👩‍👧 = 👨 + ZWJ + 👩 + ZWJ + 👧 = 5 コードポイント
  • 👨🏽‍🚀 = 👨 + 肌色 + ZWJ + 🚀 = 4 コードポイント
  • 🏳️‍🌈 = 旗 + 異体字セレクタ + ZWJ + 虹 = 4 コードポイント

UTF-16 でカウントすると、家族絵文字は 11 ユニットを超えることもあります。 見た目は 1 文字、コードポイントでは 5 つ、UTF-16 ユニットでは 10 つ、書記素クラスタでは 1 つ。 どの粒度でカウントされるかで、文字数制限への影響がまったく変わります。

肌色修飾子と異体字セレクタ

👋🏽 のような肌色付きジェスチャーは、ベースの絵文字 + 肌色修飾子の 2 コードポイントで構成されます。 さらに、絵文字としての表示を強制する異体字セレクタ (U+FE0F) が後続するパターンもあります。

  • 👋 (素手) = 1 コードポイント
  • 👋🏽 (肌色付き) = 2 コードポイント
  • ❤️ (赤いハート) = 2 コードポイント (♥ + U+FE0F)

❤️ が「ハート 1 つで 2 文字」になる理由は異体字セレクタです。 テキスト表示の ♥ と区別するため、絵文字としての表示を要求する不可視の制御コードが付随しています。

主要プラットフォームのカウントロジック

X (旧 Twitter) - 重み付きカウント

X は 2018 年から「重み付き文字カウント」を採用しています。 ASCII 文字や一部の通貨記号は 1 文字、それ以外 (日本語・絵文字含む) は 2 文字としてカウント。 日本語ユーザーが 280 文字ではなく実質 140 文字までしか書けないのはこの仕組みが理由です。

絵文字は「見た目 1 つ」を 2 文字とカウントする独自実装で、ZWJ シーケンスでも見た目 1 つなら 2 文字扱い。 サロゲートペア単位ではなく、書記素クラスタ単位で重みを付けている点が特徴です。

Instagram - キャプションと bio で挙動が違う

Instagram のキャプション (2200 文字) は寛容で、絵文字の見た目 1 つをほぼ 1 文字として扱います。 一方で bio (150 文字) はより厳しく、ZWJ シーケンスや特殊な絵文字でカウントが膨らむ場面があります。 bio のデザインに ZWJ 系絵文字を使うと「文字数が足りない」と感じる原因です。

LINE - メッセージは寛容、ステータスは厳しい

LINE のメッセージ本文の上限 (10000 文字) は実質的に絵文字数を気にする必要はありません。 ただしプロフィールのステータスメッセージ (500 文字) は UTF-16 ユニット単位に近いカウントで、 家族絵文字を多用すると思った以上に枠を消費します。

Discord - グレースフル

Discord は内部的にコードポイント単位に近いカウントを採用しており、 絵文字 1 つはほぼ 1 文字として扱われます。bio の文字数制限が緩く感じる理由です。

独自の考察 - なぜプラットフォーム間でカウントが違うのか

プラットフォームのカウントロジックは「ユーザーが直感的に納得するかどうか」と 「内部実装の歴史的経緯」のせめぎあいで決まっています。

書記素クラスタ単位の正確なカウントは、Unicode 標準ライブラリ (ICU) や grapheme-splitter のような 専用ライブラリを必要とします。古くからあるサービスほど内部処理が UTF-16 ベースで作られているため、 後から正確な書記素単位カウントに変えるのはコストが高い。結果として「現実的な妥協」として、 UTF-16 ユニットや独自の重み付けが残っています。

ユーザーから見れば「同じ絵文字が場所によって違う文字数になる」のは不可解ですが、 各プラットフォームの内部事情の現れと捉えると、なぜそうなっているかが見えてきます。

実用的な対処法

1. 重要な投稿は事前にカウントを確認

bio や 1 投稿で勝負するキャプションでは、実際にプラットフォームのフォームに貼り付けて、 残り文字数表示を見るのが確実です。外部の文字数カウンタは多くがコードポイント単位で、 実際のプラットフォームのカウントと一致しないことがあります。

2. 装飾系絵文字は ZWJ を避ける

絵文字アートやプロフィール装飾では、ZWJ シーケンスより単純な絵文字を選んだ方が文字数が抑えられます。 🌸 ☕ 📚 ✨ のような単一コードポイントの絵文字を主役にすると、見た目の華やかさを保ったまま文字数効率が上がります。

3. ❤️ の代わりに ♥

どうしても 1 文字節約したい場面では、❤️ (絵文字 2 コードポイント) ではなくテキストハート ♥ (1 コードポイント) を選ぶ手があります。 ただし、プラットフォームによってはモノクロ表示になるため、見た目とのトレードオフです。

4. 自前で実装するならライブラリを使う

自社サービスでテキストフォームを実装するなら、書記素クラスタ単位でカウントするのが最も誠実です。 JavaScript なら Intl.Segmenter (モダンブラウザ標準) や grapheme-splitter ライブラリが利用できます。 絵文字利用者を不利にしない設計は、現代の Web サービスの基本マナーになりつつあります。

まとめ

絵文字の文字数は、コードポイント・コードユニット・書記素クラスタのどのレイヤーで数えるかで変わります。 プラットフォームごとのロジックを把握し、重要な投稿では実機で残量を確認するのが確実です。 絵文字アートを工夫したいなら、ZWJ を避けて単一コードポイントの絵文字を活かすと文字数効率が上がります。

EmoArt の 探すページ では、シンプルな単一絵文字や装飾文字を組み合わせた combo を多数公開しています。 文字数を抑えながら印象的なプロフィールを作りたい人に役立つはずです。

この記事は役に立ちましたか?