Prompt

[絵文字]にマッチする正規表現

絵文字にマッチする正規表現は、単一のコードポイントだけでなく「複数の文字が組み合わさって1つの絵文字に見えるもの(絵文字シーケンス)」を考慮する必要があるため、実はかなり奥が深いです。

2026年現在、最も推奨されるのは Unicode Property Escapes (\p{...}) を活用する方法です。


1. 最もモダンで正確な書き方 (JavaScript / TypeScript)

モダンなブラウザや Node.js 環境では、v フラグ(Unicode Property Escapes の拡張版)を使用するのが「一意な正解」に最も近いです。

JavaScript

// Unicode 16.0 以降の絵文字シーケンスにも対応
const emojiRegex = /\p{RGI_Emoji}/v;

// 文字列内のすべての絵文字を抽出する場合
const text = "こんにちは!🌟 家族 👨‍👩‍👧‍👦 旗 🇯🇵";
const matches = text.match(/\p{RGI_Emoji}/gv);

console.log(matches); 
// ["🌟", "👨‍👩‍👧‍👦", "🇯🇵"]

ポイント:

  • \p{Emoji} だけだと「0〜9」の数字や「#」「*」なども絵文字候補(Emoji_Component)としてマッチしてしまいます。

  • \p{RGI_Emoji} は「一般的に表示されるべき絵文字セット(Recommended for General Interchange)」を指すため、合成された絵文字(家族、国旗など)を1つの塊として正しく扱えます。


2. Python での実装

Python 標準の re モジュールは \p{...} をサポートしていないため、サードパーティ製の regex ライブラリを使うのが一般的です。

Python

import regex

text = "こんにちは!🌟 👨‍👩‍👧‍👦 🇯🇵"
# Extended_Pictographic を使うのが現代的な手法
emoji_pattern = regex.compile(r'\p{Extended_Pictographic}')

matches = emoji_pattern.findall(text)
print(matches) 
# ['🌟', '👨‍👩‍👧‍👦', '🇯🇵']

3. なぜ「昔ながらの範囲指定」はダメなのか

昔のブログ記事などで見かける [ \u1F600-\u1F64F ] のような範囲指定(レンジ)には、以下の 「スイスチーズの穴」 があります。

  1. 新しい絵文字に対応できない: Unicode は毎年更新されるため(2025年には Unicode 16.0 が登場)、ハードコードした範囲外に新しい絵文字が追加されると即座にリンク切れならぬ「マッチ漏れ」が起きます。

  2. 結合文字の崩壊: 👨‍👩‍👧‍👦(家族)は、内部的には 👨 + ZWJ + 👩 + ZWJ + 👧 + ZWJ + 👦 という 7 つのコードポイントの羅列です。単純な範囲指定だと、これらがバラバラにマッチしてしまい、データの整合性が壊れます。


見落とされがちな視点:\p{Emoji_Presentation} vs \p{Extended_Pictographic}

  • \p{Emoji_Presentation}: 「デフォルトで絵文字として表示されるべき文字」にマッチします。

  • \p{Extended_Pictographic}: 将来の絵文字(まだ定義されていない結合パターンなど)を予見して、絵文字になりうる「絵記号」全体をカバーします。

    • 2026年のトレンド: より堅牢に「絵文字っぽいもの」をすべて拾いたいなら Extended_Pictographic を選ぶのが安全です。

結論

  • JSなら: /\p{RGI_Emoji}/v

  • 汎用的なプロパティなら: \p{Extended_Pictographic}

もし、「特定の言語や古い環境でも動く、泥臭いけど確実な正規表現」 が必要なら、emoji-regex-xs のようなライブラリが生成するパターンをコピペするのが一番の近道だよ。

次は、「実際にこの正規表現を使って、バリデーション(絵文字入力を禁止する、あるいは許可する)の実装コード」 を書いてみる?