Dividir Mensajes Largos para Redes Sociales: Una Utilidad PHP para Límites de Caracteres
Introducción
Al construir chatbots, herramientas para redes sociales o aplicaciones con IA, inevitablemente enfrentarás un desafío común: el texto que quieres enviar es más largo de lo que la plataforma permite.
Los DMs de Instagram tienen un límite de 1,000 caracteres. Twitter/X limita los posts a 280 caracteres. Los mensajes SMS se dividen en 160 caracteres. Y cuando trabajas con respuestas generadas por IA, rara vez respetan estos límites.
El enfoque ingenuo—cortar el texto exactamente en el límite de caracteres—resulta en palabras cortadas y mensajes ilegibles. Lo que necesitas es una división inteligente que respete los límites de las palabras y produzca fragmentos limpios y legibles.
El Problema
Considera este escenario: tu asistente de IA genera una respuesta de 3,000 caracteres para una consulta de un cliente. Necesitas enviarla por DM de Instagram (límite de 1,000 caracteres). Simplemente cortar en la posición 1000 podría producir:
...y el mejor enfoque sería reconfiEn lugar de:
...y el mejor enfoque seríaTus usuarios merecen algo mejor.
La Solución
Aquí hay una función utilitaria PHP que divide mensajes largos en límites naturales—espacios y saltos de línea—respetando tu límite de caracteres:
public static function splitMessageByLength(string $message, int $length = 4096): array
{
// Normaliza saltos de línea a \n
$message = str_replace("\r\n", "\n", $message);
$message = str_replace("\r", "\n", $message);
$messages = [];
$current_message = '';
// Recorre el mensaje carácter por carácter
for ($i = 0, $count = mb_strlen($message, 'UTF-8'); $i < $count; $i++) {
$char = mb_substr($message, $i, 1, 'UTF-8');
// Agrega el carácter
$current_message .= $char;
// Verifica si el mensaje actual excede el límite
if (mb_strlen($current_message, 'UTF-8') >= $length) {
// Encuentra la última ocurrencia de espacio o salto de línea
$lastSpace = mb_strrpos($current_message, ' ', 0, 'UTF-8');
$lastBreak = mb_strrpos($current_message, "\n", 0, 'UTF-8');
// Determina la posición de corte (prefiere salto de línea sobre espacio)
$splitPos = $lastBreak !== false ? $lastBreak : $lastSpace;
// Si no hay espacio o salto, fuerza corte en el límite máximo
if ($splitPos === false || $splitPos === 0) {
$splitPos = $length;
}
// Agrega el fragmento actual al array de mensajes
$messages[] = mb_substr($current_message, 0, $splitPos, 'UTF-8');
// Inicia el siguiente fragmento con el contenido restante
$current_message = mb_substr($current_message, $splitPos, null, 'UTF-8');
}
}
// Agrega el resto si existe
if (!empty($current_message)) {
$messages[] = $current_message;
}
// Limpieza: elimina espacios y filtra strings vacíos
$messages = array_map('trim', $messages);
$filtered_messages = array_filter($messages, function ($message) {
return (bool) $message;
});
return array_values($filtered_messages);
}Cómo Funciona
El algoritmo sigue estos pasos:
Normaliza saltos de línea - Convierte saltos de Windows (
\r\n) y Mac antiguo (\r) al estilo Unix (\n) para un manejo consistente.Recorre carácter por carácter - Usa funciones multibyte seguras (
mb_strlen,mb_substr) para manejar correctamente caracteres Unicode como emojis y letras acentuadas.Detección inteligente de límites - Cuando se alcanza el límite, busca hacia atrás el último espacio o salto de línea. Los saltos de línea se prefieren ya que representan puntos de división más naturales.
Fallback para casos extremos - Si no existe un punto de división adecuado (ej: una sola palabra muy larga), fuerza la división en el límite exacto.
Limpieza - Elimina espacios de cada fragmento y descarta strings vacíos que puedan resultar de la división.
Ejemplos de Uso
Uso Básico
$mensajeLargo = "Este es un mensaje muy largo que necesita ser dividido...";
$partes = TextUtil::splitMessageByLength($mensajeLargo, 100);
foreach ($partes as $indice => $parte) {
echo "Parte " . ($indice + 1) . ": " . $parte . "\n";
}Límites Específicos por Plataforma
class DivisorMensajes
{
const INSTAGRAM_DM = 1000;
const TWITTER = 280;
const SMS = 160;
const WHATSAPP = 4096;
const TELEGRAM = 4096;
public static function paraInstagram(string $mensaje): array
{
return TextUtil::splitMessageByLength($mensaje, self::INSTAGRAM_DM);
}
public static function paraTwitter(string $mensaje): array
{
return TextUtil::splitMessageByLength($mensaje, self::TWITTER);
}
public static function paraSMS(string $mensaje): array
{
return TextUtil::splitMessageByLength($mensaje, self::SMS);
}
}Con Respuestas de IA
// Obtiene respuesta de la IA (puede ser muy larga)
$respuestaIA = $anthropicService->chat($prompt);
// Divide para envío por DM de Instagram
$partes = TextUtil::splitMessageByLength($respuestaIA, 1000);
foreach ($partes as $parte) {
$instagramApi->sendDirectMessage($userId, $parte);
// Agrega delay para mantener orden de mensajes
usleep(500000); // 500ms
}Referencia de Límites por Plataforma
| Plataforma | Límite | Notas |
|---|---|---|
| Instagram DM | 1,000 | Por mensaje |
| Instagram Caption | 2,200 | Truncado en 125 en el feed |
| Twitter/X | 280 | Usuarios premium tienen más |
| SMS | 160 | Mayor = múltiples segmentos |
| 4,096 | Por mensaje | |
| Telegram | 4,096 | Por mensaje |
| Facebook Post | 63,206 | Pero 40-80 caracteres es ideal |
| 3,000 | Truncado en 140 en el feed |
Engagement Óptimo
Estudios muestran que mensajes más cortos generan mejor engagement. Posts en Twitter con menos de 100 caracteres tienen 17% más engagement. Captions de Instagram entre 138-150 caracteres tienen mejor rendimiento.
Mejoras a Considerar
Agregando Números de Parte
public static function dividirConNumeros(string $mensaje, int $limite): array
{
$partes = self::splitMessageByLength($mensaje, $limite - 10); // Reserva espacio
$total = count($partes);
if ($total === 1) {
return $partes;
}
return array_map(function ($parte, $indice) use ($total) {
return $parte . "\n\n(" . ($indice + 1) . "/" . $total . ")";
}, $partes, array_keys($partes));
}Preservando Estructura de Párrafos
public static function dividirPorParrafos(string $mensaje, int $limite): array
{
$parrafos = explode("\n\n", $mensaje);
$partes = [];
$actual = '';
foreach ($parrafos as $parrafo) {
$prueba = $actual ? $actual . "\n\n" . $parrafo : $parrafo;
if (mb_strlen($prueba, 'UTF-8') <= $limite) {
$actual = $prueba;
} else {
if ($actual) {
$partes[] = $actual;
}
// Si un solo párrafo excede el límite, usa división por carácter
if (mb_strlen($parrafo, 'UTF-8') > $limite) {
$partes = array_merge($partes,
self::splitMessageByLength($parrafo, $limite));
$actual = '';
} else {
$actual = $parrafo;
}
}
}
if ($actual) {
$partes[] = $actual;
}
return $partes;
}Consideraciones sobre Emojis
Los emojis pueden tener 1-4 bytes pero cuentan como 1-2 caracteres dependiendo de la plataforma. Prueba cuidadosamente con contenido rico en emojis para asegurar una división precisa.
Conclusión
Dividir mensajes largos puede parecer trivial, pero hacerlo correctamente—respetando límites de palabras, manejando Unicode adecuadamente y limpiando los resultados—marca la diferencia entre una aplicación profesional y una experiencia frustrante para el usuario.
Los puntos clave:
- Siempre usa funciones de string multibyte para seguridad Unicode
- Prefiere puntos de división naturales (saltos de línea > espacios > cortes forzados)
- Limpia los resultados eliminando espacios y filtrando fragmentos vacíos
- Considera optimizaciones específicas por plataforma para tu caso de uso
Esta utilidad se vuelve especialmente valiosa al integrar servicios de IA en plataformas de mensajería, donde el tamaño de las respuestas es impredecible y los límites de caracteres son estrictos.

