为社交媒体分割长消息:处理字符限制的 PHP 工具
简介
在构建聊天机器人、社交媒体工具或 AI 驱动的应用程序时,你将不可避免地面临一个常见挑战:你想发送的文本超过了平台允许的长度。
Instagram 私信限制为 1,000 个字符。Twitter/X 将帖子限制在 280 个字符。SMS 消息在 160 个字符处分割。而当你处理 AI 生成的回复时,它们很少遵守这些限制。
简单的方法——在字符限制处精确截断文本——会导致单词被切断和消息难以阅读。你需要的是智能分割,能够尊重单词边界并产生干净、可读的片段。
问题
考虑这个场景:你的 AI 助手为客户查询生成了 3,000 字符的回复。你需要通过 Instagram 私信发送(限制 1,000 字符)。简单地在位置 1000 处截断可能产生:
...最好的方法是重新配而不是:
...最好的方法是你的用户值得更好的体验。
解决方案
这是一个 PHP 工具函数,它在自然边界——空格和换行符——处分割长消息,同时遵守你的字符限制:
public static function splitMessageByLength(string $message, int $length = 4096): array
{
// 将换行符标准化为 \n
$message = str_replace("\r\n", "\n", $message);
$message = str_replace("\r", "\n", $message);
$messages = [];
$current_message = '';
// 逐字符遍历消息
for ($i = 0, $count = mb_strlen($message, 'UTF-8'); $i < $count; $i++) {
$char = mb_substr($message, $i, 1, 'UTF-8');
// 添加字符
$current_message .= $char;
// 检查当前消息是否超过限制
if (mb_strlen($current_message, 'UTF-8') >= $length) {
// 找到最后一个空格或换行符的位置
$lastSpace = mb_strrpos($current_message, ' ', 0, 'UTF-8');
$lastBreak = mb_strrpos($current_message, "\n", 0, 'UTF-8');
// 确定分割位置(优先选择换行符而非空格)
$splitPos = $lastBreak !== false ? $lastBreak : $lastSpace;
// 如果没有空格或换行符,强制在最大长度处分割
if ($splitPos === false || $splitPos === 0) {
$splitPos = $length;
}
// 将当前片段添加到消息数组
$messages[] = mb_substr($current_message, 0, $splitPos, 'UTF-8');
// 用剩余内容开始下一个片段
$current_message = mb_substr($current_message, $splitPos, null, 'UTF-8');
}
}
// 如果有剩余内容则添加
if (!empty($current_message)) {
$messages[] = $current_message;
}
// 清理:去除空白并过滤空字符串
$messages = array_map('trim', $messages);
$filtered_messages = array_filter($messages, function ($message) {
return (bool) $message;
});
return array_values($filtered_messages);
}工作原理
该算法遵循以下步骤:
标准化换行符 - 将 Windows (
\r\n) 和旧版 Mac (\r) 换行符转换为 Unix 风格 (\n),以保持一致的处理。逐字符遍历 - 使用多字节安全函数(
mb_strlen、mb_substr)来正确处理 Unicode 字符,如表情符号和带重音的字母。智能边界检测 - 当达到限制时,向后查找最后一个空格或换行符。换行符优先,因为它们代表更自然的分割点。
边缘情况回退 - 如果不存在合适的分割点(例如,一个非常长的单词),则在精确限制处强制分割。
清理 - 去除每个片段的空白,并删除可能因分割而产生的空字符串。
使用示例
基本用法
$longMessage = "这是一条需要被分割的非常长的消息...";
$chunks = TextUtil::splitMessageByLength($longMessage, 100);
foreach ($chunks as $index => $chunk) {
echo "第 " . ($index + 1) . " 部分: " . $chunk . "\n";
}特定平台限制
class MessageSplitter
{
const INSTAGRAM_DM = 1000;
const TWITTER = 280;
const SMS = 160;
const WHATSAPP = 4096;
const TELEGRAM = 4096;
public static function forInstagram(string $message): array
{
return TextUtil::splitMessageByLength($message, self::INSTAGRAM_DM);
}
public static function forTwitter(string $message): array
{
return TextUtil::splitMessageByLength($message, self::TWITTER);
}
public static function forSMS(string $message): array
{
return TextUtil::splitMessageByLength($message, self::SMS);
}
}处理 AI 回复
// 获取 AI 回复(可能非常长)
$aiResponse = $anthropicService->chat($prompt);
// 为 Instagram 私信发送进行分割
$parts = TextUtil::splitMessageByLength($aiResponse, 1000);
foreach ($parts as $part) {
$instagramApi->sendDirectMessage($userId, $part);
// 添加延迟以保持消息顺序
usleep(500000); // 500毫秒
}平台字符限制参考
| 平台 | 限制 | 备注 |
|---|---|---|
| Instagram 私信 | 1,000 | 每条消息 |
| Instagram 标题 | 2,200 | 在信息流中截断为 125 |
| Twitter/X | 280 | 高级用户有更多 |
| SMS | 160 | 更长 = 多个分段 |
| 4,096 | 每条消息 | |
| Telegram | 4,096 | 每条消息 |
| Facebook 帖子 | 63,206 | 但 40-80 字符最佳 |
| 3,000 | 在信息流中截断为 140 |
最佳互动效果
研究表明,较短的消息能获得更好的互动。Twitter 上少于 100 个字符的帖子互动率高 17%。Instagram 标题在 138-150 个字符之间效果最佳。
值得考虑的增强功能
添加部分编号
public static function splitWithNumbers(string $message, int $length): array
{
$chunks = self::splitMessageByLength($message, $length - 10); // 预留空间
$total = count($chunks);
if ($total === 1) {
return $chunks;
}
return array_map(function ($chunk, $index) use ($total) {
return $chunk . "\n\n(" . ($index + 1) . "/" . $total . ")";
}, $chunks, array_keys($chunks));
}保留段落结构
public static function splitByParagraphs(string $message, int $length): array
{
$paragraphs = explode("\n\n", $message);
$chunks = [];
$current = '';
foreach ($paragraphs as $para) {
$test = $current ? $current . "\n\n" . $para : $para;
if (mb_strlen($test, 'UTF-8') <= $length) {
$current = $test;
} else {
if ($current) {
$chunks[] = $current;
}
// 如果单个段落超过限制,使用字符分割
if (mb_strlen($para, 'UTF-8') > $length) {
$chunks = array_merge($chunks,
self::splitMessageByLength($para, $length));
$current = '';
} else {
$current = $para;
}
}
}
if ($current) {
$chunks[] = $current;
}
return $chunks;
}表情符号注意事项
表情符号可能是 1-4 个字节,但根据平台不同可能算作 1-2 个字符。请使用包含大量表情符号的内容进行充分测试,以确保准确分割。
总结
分割长消息可能看起来微不足道,但正确地做到这一点——尊重单词边界、正确处理 Unicode、清理结果——这是专业应用程序和令人沮丧的用户体验之间的区别。
关键要点:
- 始终使用多字节字符串函数以确保 Unicode 安全
- 优先选择自然分割点(换行符 > 空格 > 强制截断)
- 通过去除空白和过滤空片段来清理结果
- 根据你的用例考虑特定平台的优化
当将 AI 服务集成到消息平台时,这个工具变得特别有价值,因为回复长度是不可预测的,而字符限制是严格的。

