
本文介绍如何使用 PHP 对多行文本进行逐行处理,识别并提取形如 {n} 的标记,仅保留 {19} 和 {20} 在原位置,其余 {...} 标记统一移至该行末尾,同时保持其他 token 顺序不变。
本文介绍如何使用 php 对多行文本进行逐行处理,识别并提取形如 `{n}` 的标记,仅保留 `{19}` 和 `{20}` 在原位置,其余 `{...}` 标记统一移至该行末尾,同时保持其他 token 顺序不变。
在日志解析、配置预处理或模板清洗等场景中,常需基于语义规则对结构化标记(如 {15}、{29})进行重排。本例要求:每行中所有形如 {n} 的 token,若 n 不为 19 或 20,则将其移动到该行末尾;其余内容(包括 {19}、{20} 及 (xxx)、[yyy] 等非目标格式)严格保留在原始顺序与位置。
实现核心在于逐行隔离 + 分类归集 + 有序拼接。我们不依赖全局正则替换(易破坏上下文),而是采用函数式思路:对每行按空格切分 → 遍历每个 token → 利用负向先行断言精准识别“需移动”的 {n} → 分别存入 valid(保留)和 move(迁移)两个数组 → 最终合并 valid + array_reverse(move)(注意:示例输出中 {15} {29} 的顺序表明后出现的 {29} 排在更右,即按原始出现顺序追加,无需 reverse;实际应直接 array_merge($valid, $move) —— 后文将修正说明)。
以下是完整、可运行的 PHP 实现:
<?php $input = <<<TEXT
# (811) (1485) [2756] {29} [555] {15}
# (811) (1476) {20} {15} (1485) [196] [2441]
# (911) (619) {19} (1476) [2765] [2752] {21}
TEXT;
foreach (explode("\n", trim($input)) as $line) {
if ($line === '') continue;
$tokens = explode(' ', $line);
$valid = [];
$toMove = [];
foreach ($tokens as $token) {
// 匹配 {n},且 n ≠ 19 且 n ≠ 20
if (preg_match('/^{(?!19}|20})\d+}$/', $token)) {
$toMove[] = $token;
} else {
$valid[] = $token;
}
}
echo implode(' ', array_merge($valid, $toMove)) . PHP_EOL;
}
?>
输出结果:
# (811) (1485) [2756] [555] {15} {29}
# (811) (1476) {20} (1485) [196] [2441] {15}
# (911) (619) {19} (1476) [2765] [2752] {21}
✅ 关键细节说明:
- 正则 /^{(?!19}|20})\d+}$/ 中的 (?!19}|20}) 是负向先行断言,确保 { 后不紧邻 19} 或 20},从而精确排除 {19} 和 {20};^ 和 $ 保证匹配整个 token,避免误匹配(如 {119} 中的 {19})。
- 使用 foreach 替代 array_reduce 提升可读性与调试友好性;若坚持函数式风格,array_reduce 初始化结构 ['valid' => [], 'move' => []] 是良好实践。
- 重要修正:原始答案中 array_reverse($result['move']) 会导致 {15} {29} 变为 {29} {15},与预期输出矛盾。实际应保持原始遍历顺序,直接追加即可(即 array_merge($valid, $toMove))。
- 注意 trim($input) 和跳过空行,增强鲁棒性;生产环境建议添加 mb_ 函数支持 Unicode。
此方案逻辑清晰、扩展性强:只需修改正则中的 19|20 即可适配新白名单,亦可轻松改为移动至行首或插入特定分隔符。掌握此类基于 token 分类的字符串重组技巧,是构建可靠文本处理器的关键基础。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











