最終更新:

絵文字の文字数カウント|1 文字に見えて複数文字?仕組みを解説

約 7 分で読めます

SNS やメッセージアプリで絵文字を使ったとき、文字数が予想以上に増えた経験はありませんか。全角と半角の文字数の違いと同様に、絵文字の文字数カウントにも独特の仕組みがあります。

絵文字の歴史と Unicode バージョン別の推移

絵文字が世界的に広まる起点となったのは 1999 年、NTT ドコモの栗田穣崇氏が i-mode 向けに作成した 176 種類のセットです。12×12 ピクセルのドット絵として誕生した絵文字は、当初は日本の携帯キャリア各社 (ドコモ・au・ソフトバンク) が独自に実装しており、キャリア間で絵文字が文字化けする問題が日常的に発生していました。この互換性問題を解決するため、Google と Apple が Unicode Consortium に絵文字の標準化を提案し、2010 年の Unicode 6.0 で 722 種類が正式採用されました。

その後も Unicode のバージョンアップに合わせて絵文字は追加されていますが、追加数はバージョンごとに大きく違います。公開資料で追える代表的なバージョンは次のとおりです。

Unicode バージョンリリース年追加された絵文字数
6.02010722
7.02014約 250
8.0201541
16.020248

ここで気をつけたいのは、絵文字の「総数」が数え方の定義で変わることです。単独のコードポイントだけを数えるのか、ZWJ シーケンスや肌の色を指定した派生形まで別個に数えるのかで、同じ時点の集計でも数字が大きく変わります。Unicode Consortium 自身の絵文字集計 (Emoji 17.0 版) では、派生形を含めた総数を 3,953 件としています。

初期の一括採用に比べると、2020 年代の新規追加数は明らかに小さくなっています。Unicode Consortium は「既存の絵文字やシーケンスで表現できてしまうもの」を除外条件として明示しており、既存パーツの組み合わせで代替できる提案は採用されません。提案者の側も、Google 検索や Google トレンド、Google Books Ngram Viewer での使用頻度の証拠と、既存の絵文字と見分けがつく独自性の根拠を示す必要があります。

エンコーディング別のバイトサイズ実測データ

絵文字は Unicode の基本と文字コードに基づいてエンコードされますが、エンコーディング方式によってバイトサイズが大きく異なります。以下は代表的な絵文字の実測データです。

絵文字見た目コードポイント数UTF-8 バイト数UTF-16 バイト数UTF-32 バイト数
😀 (U+1F600)1 文字1444
👍🏻 (U+1F44D U+1F3FB)1 文字2888
👨‍👩‍👧‍👦1 文字7252228
🇯🇵 (U+1F1EF U+1F1F5)1 文字2888
1️⃣ (U+0031 U+FE0F U+20E3)1 文字37612
🏳️‍🌈1 文字4141216

UTF-8 では基本多言語面 (BMP) 外のコードポイントは 1 つあたり 4 バイトを消費します。UTF-16 ではサロゲートペア (2 つの 16 ビットユニット) で表現するため同じく 4 バイトです。UTF-32 は固定長で 1 コードポイント = 4 バイトのため計算は単純ですが、メモリ効率は最も悪くなります。家族絵文字 👨‍👩‍👧‍👦 の場合、UTF-8 で 25 バイトを消費する点は、データベースのカラムサイズ設計で特に注意が必要です。

ZWJ・Variation Selector・サロゲートペアの仕組み

Unicode では、複数のコードポイントを ZWJ (Zero Width Joiner: ゼロ幅接合子、U+200D) で結合して 1 つの絵文字を表現する仕組みがあります。家族の絵文字 👨‍👩‍👧‍👦 は「男性 (U+1F468) + ZWJ + 女性 (U+1F469) + ZWJ + 女の子 (U+1F467) + ZWJ + 男の子 (U+1F466)」の 7 コードポイントで構成されています。

この設計が採用された背景には、絵文字の組み合わせの爆発的な増加があります。たとえば 4 人家族の絵文字を、肌の色 5 段階を人物ごとに選べる形で個別に登録すると、それだけで 5 の 4 乗 = 625 通り、さらに家族構成の違いを掛け合わせれば数千通りに膨れ上がります。ZWJ による合成方式なら、基本パーツの組み合わせで同じ表現力を確保できます。Unicode Consortium はこの方式により、コードポイントの枯渇を防ぎつつ多様性を実現しました。

家族絵文字 👨‍👩‍👧‍👦 の内部構造 - 見た目 1 文字が 7 コードポイント 25 バイトになるまで
画面上の見た目 👨‍👩‍👧‍👦 1
コードポイント 👨 U+1F468 ZWJ U+200D 👩 U+1F469 ZWJ U+200D 👧 U+1F467 ZWJ U+200D 👦 U+1F466 7
UTF-16 コードユニット数 👨 2 ZWJ 1 👩 2 ZWJ 1 👧 2 ZWJ 1 👦 2 11
UTF-8 バイト数 👨 4 ZWJ 3 👩 4 ZWJ 3 👧 4 ZWJ 3 👦 4 25

破線のマスが画面に表示されない ZWJ です。絵文字 4 個は BMP 外のコードポイントなのでサロゲートペア 2 ユニット・UTF-8 で 4 バイトを消費し、ZWJ 3 個は 1 ユニット・3 バイトです。同じ 1 つのアイコンが、数える層を変えるだけで 1 (Swift の .count)、7 (Python 3 の len())、11 (JavaScript の .length) と別の答えになります。UTF-8 で 25 バイトに達するため、3 バイトまでしか扱えない MySQL の utf8 では保存できません。

ZWJ 以外にも、絵文字の表示を制御する不可視のコードポイントが存在します。

JavaScript の内部文字列表現は UTF-16 を採用しているため、BMP 外の絵文字 (U+10000 以上) はサロゲートペアとして 2 つの 16 ビットユニットで表現されます。これが "😀".length が 1 ではなく 2 を返す根本的な理由です。サロゲートペアの上位 (U+D800〜U+DBFF) と下位 (U+DC00〜U+DFFF) を分割してしまうと、不正な文字列が生成されるため、文字列の切り詰め処理では特に注意が必要です。

プラットフォーム別の絵文字カウントと表示差異

同じ絵文字でも、Apple・Google・Samsung・Microsoft の各プラットフォームでデザインが大きく異なる点にも注意が必要です。例えば 🔫 (ピストル) は Apple がおもちゃの水鉄砲デザインに変更した後、他社も追随しましたが、変更のタイミングにはばらつきがありました。マーケティングや UI デザインで絵文字の見た目に依存する場合は、主要プラットフォームでの表示を事前に確認することを推奨します。

プログラミング言語別の文字数カウントの違い

同じ絵文字でも、プログラミング言語によって length の返す値が異なります。これは各言語の内部文字列表現の違いに起因します。

言語 / メソッド"😀""👍🏻""👨‍👩‍👧‍👦"カウント単位
JavaScript .length2411UTF-16 コードユニット
JavaScript [...str].length127Unicode コードポイント
Python 3 len()127Unicode コードポイント
Rust .len()4825UTF-8 バイト数
Rust .chars().count()127Unicode コードポイント
Swift .count111書記素クラスタ
Go len()4825UTF-8 バイト数
Java .length()2411UTF-16 コードユニット

Swift だけが書記素クラスタ単位でカウントするため、どの絵文字でも見た目どおり 1 を返します。JavaScript や Java は UTF-16 ベースのため、BMP 外の絵文字はサロゲートペアで 2 としてカウントされます。Rust と Go はバイト数を返すため、絵文字の文字数カウントには不向きです。開発者は自分が使う言語の length が何を返すのかを正確に把握しておく必要があります。

よくある失敗パターンと対策

開発者向け: 絵文字を正確にカウントする方法

  1. Intl.Segmenter による書記素クラスタ分割: 国際化 API (ECMA-402) で標準化された Intl.Segmenter は、書記素クラスタ (ユーザーが「1 文字」と認識する単位) で文字列を分割できます。[...new Intl.Segmenter().segment(str)].length で、絵文字を含む文字列の「見た目の文字数」を正確に取得できます。Chrome 87 以降、Safari 14.1 以降、Node.js 16 以降で利用でき、Firefox は 125 以降での対応です (実装状況は 2026 年 8 月時点)。
  2. 正規表現による絵文字検出と除去: Unicode プロパティエスケープ /\p{Emoji_Presentation}/u を使えば、文字列中の絵文字を検出・除去できます。ただし \p{Emoji} は数字 (0-9) や # なども含むため、絵文字のみを対象にする場合は \p{Emoji_Presentation} または \p{Extended_Pictographic} を使い分ける必要があります。
  3. テスト用の絵文字セット: 開発時のテストには、以下の 5 カテゴリを最低限カバーすると主要なエッジケースを網羅できます。(1) 基本絵文字 (😀)、(2) 肌色修飾子付き (👍🏻)、(3) ZWJ シーケンス (👨‍👩‍👧‍👦)、(4) 国旗 (🇯🇵)、(5) キーキャップシーケンス (1️⃣)。
  4. データベース設計のベストプラクティス: 絵文字を含むテキストを保存するカラムは、見た目の文字数を基準にせず、コードポイント数とバイト数の両面でサイズを設計します。MySQL では utf8mb4 を指定し、VARCHAR(N) の N は文字数なので、書記素 1 個が 7 文字分を消費し得る前提で長さを決めます。行サイズやインデックス長の見積もりでは 1 文字あたり最大 4 バイトで換算します。絵文字を多用するチャットアプリなどでは TEXT 型の使用も検討してください。

まとめ

絵文字の文字数カウントは見た目ほど単純ではありません。文字数カウントスでは絵文字を含むテキストも正確にカウントできるので、SNS 投稿前の確認にご活用ください。

この記事を共有