
本文介绍如何使用 PHP 对多行文本逐行处理,识别并保留 {19} 和 {20} 等白名单标记在原位,同时将其他形如 {数字} 的标记统一提取并追加到当前行末尾,兼顾可读性、健壮性与性能。
本文介绍如何使用 php 对多行文本逐行处理,识别并保留 `{19}` 和 `{20}` 等白名单标记在原位,同时将其他形如 `{数字}` 的标记统一提取并追加到当前行末尾,兼顾可读性、健壮性与性能。
在日志预处理、配置文件规范化或模板文本清洗等场景中,常需对结构化标记(如 {29}、{15})进行条件重排——例如仅保留 {19} 和 {20} 在原始位置,其余 {n} 类标记统一后置。这既非简单替换,也非全局移动,而是基于行级上下文 + 正则语义判断 + 有序重组的组合操作。
以下是一个高效、清晰且可维护的实现方案:
<?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;
// 按空格分割每行,初始化两类容器
$parts = explode(' ', $line);
$result = array_reduce($parts, function($acc, $token) {
// 匹配非 {19} 且非 {20} 的 {数字} 标记(支持多位数,如 {123})
if (preg_match('/^\{\d+\}$/', $token) && !preg_match('/^\{(19|20)\}$/', $token)) {
$acc['move'][] = $token;
} else {
$acc['valid'][] = $token;
}
return $acc;
}, ['valid' => [], 'move' => []]);
// 合并:原序有效部分 + 反序移动部分(使先出现的{xx}靠后,符合示例逻辑)
echo implode(' ', array_merge($result['valid'], array_reverse($result['move']))) . PHP_EOL;
}
?>
输出结果:
# (811) (1485) [2756] [555] {15} {29}
# (811) (1476) {20} (1485) [196] [2441] {15}
# (911) (619) {19} (1476) [2765] [2752] {21}
✅ 关键设计说明:
- 行级隔离:使用 explode("\n", $input) 保证每行独立处理,避免跨行误匹配;
- 精准匹配:正则 ^\{\d+\}$ 确保只匹配完整、独立的 {数字} 令牌(防止 abc{19}def 被错误捕获);
- 白名单逻辑:用 !preg_match('/^\{(19|20)\}$/', $token) 显式排除目标保留项,语义清晰、易于扩展(如后续增加 {21} 仅需修改此处);
- 后置顺序:array_reverse($result['move']) 实现“先见后置”——即输入中靠前的非白名单 {n} 在输出中位于更右侧,严格复现示例行为;
- 空格鲁棒性:trim($input) 和跳过空行,兼容首尾空白及空行输入。
⚠️ 注意事项:
- 若输入含连续空格,explode(' ', $line) 可能产生空字符串元素,建议前置 array_filter($parts, 'strlen') 过滤;
- 如需支持嵌套或转义(如 \{19\}),应改用 preg_split() 配合负向断言,但本例中无此需求;
- 性能敏感场景可将正则编译为 PREG_PATTERN_ORDER 常量或复用 preg_match() 返回值,但当前写法已具备良好可读性与实用性。
该方案以函数式思维组织流程,避免显式循环与临时变量堆砌,在保持代码简洁的同时,准确达成「条件识别 → 分类归集 → 有序拼接」的核心目标,是文本结构化处理的典型 PHP 实践范例。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











