PHP实现根据整数参数从长文本随机抽取指定词数连贯片段
实现方案
问题根因
shuffle()的作用是打乱数组元素顺序,完全不适合抽取连贯文本的场景。要实现保持原词序的随机片段抽取,不需要对数组做排序/打乱操作,只需要随机选定连续片段的起始下标,截取对应长度的连续元素即可,天然满足词序不变、语义通顺、结果随机的要求。
原有代码的其他问题
shuffle()执行成功返回布尔值true,将返回值赋值给$text后遍历,本身就会触发类型错误- 数据库查询直接拼接GET参数存在严重SQL注入风险
- 未对传入的词数参数做类型、合法性校验,传入非正整数时会出现逻辑异常
- 按空格拆分文本时未处理连续多空格的场景,会拆出无意义的空字符串元素
核心实现逻辑
- 将文章按空格拆分为词数组,过滤空值
- 校验文章总词数,若总词数小于等于要求抽取的词数,直接返回原文即可
- 计算合法的随机起始索引范围:最小为0,最大为「总词数 - 待抽取词数」,保证截取时不会出现数组越界
- 在合法范围内随机生成起始索引,从该位置开始截取指定长度的连续词元素
- 将截取到的词拼接为字符串返回即可
修正后可直接运行的代码
<?php function get_random_paragraph_from_article($article, $articleWordsCount) { // 强制将抽取词数转为正整数,过滤非法输入 $articleWordsCount = max(1, (int)$articleWordsCount); // 按空格拆分,同时过滤拆分产生的空值(处理连续多空格场景) $text_array = array_filter(explode(" ", $article), function($item){ return trim($item) !== ''; }); $totalWords = count($text_array); // 总词数不足时直接返回原文 if ($totalWords <= $articleWordsCount) { return trim(implode(" ", $text_array)); } // 计算合法起始位置的最大值,保证截取长度足够 $maxStartIndex = $totalWords - $articleWordsCount; // 随机生成起始位置 $startIndex = mt_rand(0, $maxStartIndex); // 截取连续的指定长度片段 $selectedWords = array_slice($text_array, $startIndex, $articleWordsCount); // 拼接为字符串返回,去除首尾多余空格 return trim(implode(" ", $selectedWords)); } if (isset($_GET['getRandomArticle'])) { include($_SERVER['DOCUMENT_ROOT'] . "/includes/inc-db-connection.php"); $pdo = new PDO(sprintf('%s:host=%s;dbname=%s', DRIVER, HOST, DATA), USER, PASS); // 设置PDO错误模式为异常,方便排查问题 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 预处理参数绑定,修复SQL注入风险 $keyword = "%{$_GET['q']}%"; $count = max(1, (int)$_GET['count']); $command = $pdo->prepare("SELECT * FROM `articles` WHERE `article_keyword` LIKE ? ORDER BY RAND() LIMIT 1"); $command->execute([$keyword]); while ($row = $command->fetch()) { echo get_random_paragraph_from_article($row['article_body'], $count); } } ?>
实现效果
- 截取的片段为原文连续内容,完全保留原有词序,语义连贯
- 起始下标在合法范围内随机生成,不会固定返回开头段落,多次调用返回结果随机不重复
- 增加了边界校验,不会出现数组越界、非法参数引发的运行错误
- 修复了原代码中SQL注入、返回值类型错误的问题
内容的提问来源于stack exchange,提问作者logosapp
相关产品推荐
相关产品推荐

