
本文介绍如何使用 php 的 `preg_grep()` 配合正则表达式,精准筛选出**至少包含两个相同字母(非连续亦可)**的字符串,例如 "asds"(s 出现两次)、"dfaa"(a 出现两次),而非仅匹配特定字符(如仅 'a')或要求连续重复。
要实现“匹配任意字母至少出现两次(位置不限)”的需求,关键在于捕获一个字母,再在后续内容中回溯匹配相同的字母。此时应使用带捕获组与反向引用的正则表达式:/(\p{L}).*\1/。
- (\p{L}):匹配并捕获任意 Unicode 字母(支持中文、西欧字符等,比 [a-zA-Z] 更健壮);
- .*:匹配任意数量(含零个)的非换行字符,确保两处相同字母之间可有其他字符;
- \1:反向引用第一个捕获组的内容,即要求后续再次出现完全相同的那个字母。
✅ 正确示例代码如下:
$input_lines = ["asdf", "fdas", "asds", "d fm", "dfaa", "aaaa", "aabb", "aaabb"];
$result = preg_grep('/(\p{L}).*\1/', $input_lines);
print_r($result);输出结果为:
Array
(
[2] => asds // s 出现在第1位和第3位
[4] => dfaa // a 出现在第3位和第4位
[5] => aaaa // a 多次出现
[6] => aabb // a 出现在第0、1位;b 出现在第2、3位(任一字母满足即可)
[7] => aaabb // 同上,a 或 b 均满足条件
)⚠️ 注意事项:
立即学习“PHP免费学习笔记(深入)”;
- 原问题中 explode("\n", $input_lines) 是错误用法——$input_lines 已是数组,无需 explode;直接对数组使用 preg_grep() 即可。
- 若只需匹配 ASCII 字母(如明确限定英文),可用 /([a-zA-Z]).*\1/ 替代,但 (\p{L}) 更通用、国际化友好。
- 该模式不要求重复字符相邻(区别于 /(.)\1/),因此 "asds" 能被正确匹配(首尾 s)。
- 若需排除空格、标点等干扰,可结合 trim() 或预处理,但本正则本身已通过 .* 自动跳过中间任意字符。
? 总结:解决“任意字符重复出现”类问题,核心是「捕获 + 通配 + 反向引用」三步逻辑。避免硬编码具体字符(如 /a{2}/),改用 \p{L} 提升健壮性,并始终验证输入数据结构(如确认已是数组而非需 explode 的字符串)。











