Skip to content

Detectar Mensajes con Solo Emojis en PHP

Introducción

Al construir chatbots o aplicaciones de mensajería, frecuentemente necesitarás detectar cuando un usuario envía un mensaje que contiene solo emojis. Esto es común en escenarios como:

  • Reacciones a stories de Instagram - Los usuarios frecuentemente responden solo con "❤️" o "😂"
  • Reacciones en chats - Respuestas rápidas con emoji como "👍" o "🔥"
  • Filtrado de mensajes - Tratar mensajes con solo emojis de forma diferente al texto

En este artículo, construiremos una función simple en PHP para detectar mensajes que contienen solo emojis usando expresiones regulares.

El Desafío del Unicode

Los emojis son más complejos de lo que aparentan. Lo que parece ser un único emoji puede en realidad ser múltiples caracteres Unicode combinados:

  • Emojis básicos: Puntos de código únicos como 😀 (U+1F600)
  • Modificadores de tono de piel: 👋🏽 es 👋 + 🏽 (tono de piel medio)
  • Secuencias ZWJ: 👨‍👩‍👧 es en realidad 👨 + ZWJ + 👩 + ZWJ + 👧
  • Emojis de banderas: 🇲🇽 está formado por dos símbolos indicadores regionales

Esta complejidad significa que no podemos simplemente verificar un único carácter—necesitamos un patrón regex que cubra todos los rangos Unicode de emojis.

La Implementación

Aquí hay una implementación práctica que maneja los emojis más comunes:

php
/**
 * Verifica si el texto contiene solo emojis y espacios en blanco.
 * Útil para detectar reacciones o mensajes con solo emojis.
 */
function isOnlyEmojis(?string $text): bool
{
    if (!$text || trim($text) === '') {
        return false;
    }

    // Eliminar todos los espacios en blanco
    $textWithoutWhitespace = preg_replace('/\s+/u', '', $text);

    if ($textWithoutWhitespace === '') {
        return false;
    }

    // Patrón regex Unicode para emojis
    $emojiPattern = '/^[\x{1F600}-\x{1F64F}' .  // Emoticones
        '\x{1F300}-\x{1F5FF}' .  // Símbolos y Pictogramas Diversos
        '\x{1F680}-\x{1F6FF}' .  // Transporte y Mapa
        '\x{1F700}-\x{1F77F}' .  // Símbolos Alquímicos
        '\x{1F780}-\x{1F7FF}' .  // Formas Geométricas Extendidas
        '\x{1F800}-\x{1F8FF}' .  // Flechas Suplementarias-C
        '\x{1F900}-\x{1F9FF}' .  // Símbolos y Pictogramas Suplementarios
        '\x{1FA00}-\x{1FA6F}' .  // Símbolos de Ajedrez
        '\x{1FA70}-\x{1FAFF}' .  // Símbolos y Pictogramas Extendidos-A
        '\x{1F1E6}-\x{1F1FF}' .  // Banderas (Símbolos Indicadores Regionales)
        '\x{2600}-\x{26FF}' .    // Símbolos diversos (sol, luna, estrellas)
        '\x{2700}-\x{27BF}' .    // Dingbats
        '\x{2300}-\x{23FF}' .    // Técnicos Diversos
        '\x{2B50}\x{2B55}' .     // Estrella y círculo
        '\x{231A}\x{231B}' .     // Reloj y reloj de arena
        '\x{2328}' .             // Teclado
        '\x{23CF}' .             // Símbolo de expulsar
        '\x{23E9}-\x{23F3}' .    // Símbolos de control de medios
        '\x{23F8}-\x{23FA}' .    // Símbolos de control de medios
        '\x{24C2}' .             // M en círculo
        '\x{25AA}\x{25AB}' .     // Cuadrados pequeños
        '\x{25B6}\x{25C0}' .     // Botones de reproducir
        '\x{25FB}-\x{25FE}' .    // Cuadrados
        '\x{2934}\x{2935}' .     // Flechas
        '\x{2B05}-\x{2B07}' .    // Flechas
        '\x{3030}' .             // Guión ondulado
        '\x{303D}' .             // Marca de alternancia de parte
        '\x{3297}' .             // Ideograma en círculo de Felicitaciones
        '\x{3299}' .             // Ideograma en círculo de Secreto
        '\x{FE0F}' .             // Selector de Variación-16 (presentación emoji)
        '\x{200D}' .             // Zero Width Joiner (para emojis combinados)
        ']+$/u';

    return preg_match($emojiPattern, $textWithoutWhitespace) === 1;
}

Ejemplos de Uso

php
// Emojis básicos
isOnlyEmojis('😀');           // true
isOnlyEmojis('❤️🔥');         // true
isOnlyEmojis('👍👍👍');       // true

// Con espacios en blanco (aún válido)
isOnlyEmojis('😀 😂 🎉');     // true

// Emojis combinados (secuencias ZWJ)
isOnlyEmojis('👨‍👩‍👧');         // true
isOnlyEmojis('👋🏽');          // true (modificador de tono de piel)

// Contenido mixto (no es solo emoji)
isOnlyEmojis('Hola 👋');      // false
isOnlyEmojis('Genial! 🔥');   // false
isOnlyEmojis('123');          // false

// Casos extremos
isOnlyEmojis('');             // false
isOnlyEmojis(null);           // false
isOnlyEmojis('   ');          // false (solo espacios en blanco)

Entendiendo los Rangos Unicode

Desglosemos los principales rangos Unicode en nuestro patrón:

RangoDescripciónEjemplos
1F600-1F64FEmoticones😀 😂 😍 🙄
1F300-1F5FFSímbolos y Pictogramas Diversos🌟 🎉 🔥 💡
1F680-1F6FFTransporte y Mapa🚀 ✈️ 🏠
1F900-1F9FFSímbolos Suplementarios🤖 🦄 🧠
1F1E6-1F1FFIndicadores Regionales🇺🇸 🇪🇸 🇲🇽
2600-26FFSímbolos Diversos☀️ ⭐ ♥️
FE0FSelector de VariaciónHace que símbolos de texto aparezcan como emoji
200DZero Width JoinerConecta emojis (👨‍👩‍👧)

¿Por qué incluir FE0F y 200D?

El Selector de Variación-16 (U+FE0F) le indica al sistema que renderice un carácter como emoji. El Zero Width Joiner (U+200D) conecta múltiples emojis en un emoji combinado, como emojis de familia o profesión.

Caso de Uso Práctico: Reacciones en Chatbot

Así es como podrías usar esto en un contexto de chatbot:

php
function handleIncomingMessage(string $message): void
{
    if (isOnlyEmojis($message)) {
        // Es una reacción! Manejar de forma diferente
        logReaction($message);
        // Tal vez no disparar una respuesta completa de IA para solo "👍"
        return;
    }

    // Procesar como un mensaje de texto normal
    processTextMessage($message);
}

Limitaciones

Este enfoque basado en regex tiene algunas limitaciones:

  1. Nuevos emojis: Unicode agrega nuevos emojis regularmente. El patrón puede no cubrir las adiciones más recientes.
  2. Algunos casos extremos: Ciertas combinaciones de emojis poco usadas pueden no ser detectadas.
  3. Rendimiento: Para strings muy largos, regex puede ser más lento que enfoques basados en bibliotecas.

Alternativa: Usando una Biblioteca

Para detección de emojis más completa, considera usar una biblioteca dedicada como p3k/emoji-detector:

bash
composer require p3k/emoji-detector
php
use Emoji\Detector;

$detector = new Detector();
$result = $detector->detect('Hola 👋 Mundo');

// Retorna array de emojis detectados con posiciones

El enfoque con biblioteca es más robusto, pero agrega una dependencia. Para verificaciones simples de "¿esto es solo emoji?", el enfoque con regex es ligero y suficiente.

Conclusión

Detectar mensajes con solo emojis es útil para muchas aplicaciones de mensajería. Los puntos clave son:

  1. Los emojis son complejos - Pueden ser caracteres únicos o combinaciones
  2. Usa rangos Unicode - Cubre los principales bloques de emoji en tu regex
  3. No olvides ZWJ y FE0F - Estos caracteres invisibles son esenciales para emojis combinados
  4. Considera tu caso de uso - Regex simple funciona para la mayoría de los casos; usa una biblioteca para necesidades avanzadas

El enfoque con regex mostrado aquí maneja la gran mayoría del uso real de emojis mientras mantiene tu código libre de dependencias.