PHP刽子手游戏:字符替换为下划线的函数问题求助
解决字符隐藏替换为下划线的问题
我来帮你分析下现有代码的问题,再给出能实现需求的解决方案~
先拆解现有代码的问题
代码段1的问题
- 用
sizeof($answer)获取字符串长度不合适,sizeof是为数组设计的,字符串应该用strlen()(如果是多字节字符要改用mb_strlen()),虽然部分场景下sizeof能返回字节数,但语义不对,还可能在多字节场景下出错。 str_replace($hidden[$element], '_', $hidden, $replace_count)会替换所有和目标位置相同的字符,而非仅替换当前位置。比如单词是"apple",若取到的字符是'l',会直接把两个'l'都换成下划线,导致$count瞬间累加2,可能直接超过你设定的$hideCount,而且会把重复字符全部替换,不符合“部分替换”的需求。- 循环逻辑有bug:每次固定取
sizeof($answer)-2这个位置,如果该位置已经是下划线,循环会陷入死循环,因为$count不会增加。
代码段2的问题
这段代码只是把原字符串存到Session里,然后直接返回原字符串,完全没有执行任何字符替换操作,自然达不到隐藏效果。
正确的实现方案
我们的目标是:按指定数量替换字符为下划线,且每个位置仅替换一次,不会批量替换重复字符。以下是两种场景的实现:
单字节字符版本(适用于英文、数字等)
function hide($answer) { $strLength = strlen($answer); // 和你原逻辑保持一致,计算需要隐藏的字符数 $hideCount = floor($strLength / 2) + 1; // 边界处理:避免隐藏数量超过总字符数(比如短单词场景) $hideCount = min($hideCount, $strLength); // 把字符串转成数组,方便单个字符操作 $hidden = str_split($answer); // 生成所有字符的位置数组 $positions = range(0, $strLength - 1); // 打乱位置,实现随机隐藏效果 shuffle($positions); $count = 0; foreach ($positions as $pos) { if ($count >= $hideCount) { break; } // 只替换非下划线的字符,避免重复替换 if ($hidden[$pos] !== '_') { $hidden[$pos] = '_'; $count++; } } // 把数组转回字符串返回 return implode('', $hidden); }
多字节字符版本(适用于中文、特殊字符等)
如果你的字符串包含多字节字符(比如中文),需要用多字节字符串函数处理避免乱码:
function hide($answer) { $strLength = mb_strlen($answer); $hideCount = floor($strLength / 2) + 1; $hideCount = min($hideCount, $strLength); $hidden = mb_str_split($answer); $positions = range(0, $strLength - 1); shuffle($positions); $count = 0; foreach ($positions as $pos) { if ($count >= $hideCount) { break; } if ($hidden[$pos] !== '_') { $hidden[$pos] = '_'; $count++; } } return implode('', $hidden); }
代码逻辑说明
- 先获取字符串长度,计算需要隐藏的字符数,同时做边界处理避免逻辑错误。
- 将字符串转成数组,方便逐个操作单个字符。
- 生成所有字符位置的数组并打乱,实现随机隐藏(如果需要固定位置替换,比如替换前N个字符,去掉
shuffle($positions),直接遍历前N个位置即可)。 - 遍历打乱后的位置,逐个替换非下划线字符,直到达到需要隐藏的数量。
- 最后将数组转回字符串返回。
内容的提问来源于stack exchange,提问作者edeath
相关产品推荐
相关产品推荐

