
本文详解如何遍历字符串,对目标字符(如 'l')从左到右逐次计数,并将其原位置替换为当前累计出现序号(如第1次出现→'1',第2次→'2'),支持任意长度计数,避免因数字位数增长导致索引偏移问题。
在实际开发中,常需实现“按首次/二次/第N次出现顺序标记指定字符”的需求,例如将 "helololol" 中的 'l' 替换为 1,2,3,4 得到 "he1o2o3o4",或将 'o' 替换为 "hel1l2l3l"。该任务看似简单,但直接使用 String.substring() 拼接会引发索引错位——因为每次用数字(如 "10" 代替 'l')会使字符串变长,后续字符位置前移,原下标失效。
✅ 正确思路:构建新字符串(推荐)
最稳健的方式是不修改原字符串,而是遍历并累积构建结果,同时动态维护计数器:
public static String replaceCharWithCount(String str, char target) {
StringBuilder result = new StringBuilder();
int count = 0;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c == target) {
count++;
result.append(count); // 直接追加当前序号(自动支持多位数)
} else {
result.append(c);
}
}
return result.toString();
}
// 使用示例
public static void main(String[] args) {
System.out.println(replaceCharWithCount("helololol", 'l')); // he1o2o3o4
System.out.println(replaceCharWithCount("helololol", 'o')); // hel1l2l3l
System.out.println(replaceCharWithCount("lllll", 'l')); // 12345
System.out.println(replaceCharWithCount("abcldefglhijkl", 'l')); // abc1defg2hijk3
}✅ 优势:
- 零索引偏移风险:StringBuilder 线性构建,无需关心插入位置;
- 天然支持大数:count 可达 Integer.MAX_VALUE,append(count) 自动转为 "100"、"1000" 等多字符数字;
- 时间复杂度 O(n),空间复杂度 O(n),高效且可读性强。
⚠️ 注意事项与进阶建议
- 区分大小写:target 匹配严格区分大小写,如需忽略,可先统一转为 toLowerCase() 处理源串与 target;
-
空/边界输入:建议增加校验:
if (str == null) return null;
- 性能敏感场景:若字符串极大(GB级),可改用 char[] 原地预分配+双指针,但需预先扫描一次统计最大可能位数以预留空间;
- 扩展需求:如需“仅替换第2、4、6次出现”,可改为 if (c == target && ++count % 2 == 0) 等条件逻辑。
总结
替代“边遍历边 substring 拼接”这种易出错的旧范式,应始终优先采用 StringBuilder 累积构建法——它简洁、健壮、可扩展,且天然规避了数字位数增长引发的所有索引陷阱。掌握这一模式,即可优雅解决各类“按序标记字符”的字符串处理任务。










