Java多行字符串截取:按指定行号与字符位置获取子串
Java多行字符串指定行位置截取子串解决方案
问题背景
需要实现方法public static String substring(String text, int line, int character),输入多行字符串后,返回从开头到指定零基行号、该行指定零基字符位置的子串。示例:
- 输入字符串:
hello world how are you? - 调用
substring(text, 0, 2)→ 返回"he" - 调用
substring(text, 1, 3)→ 返回"hello\nwor"(保留原字符串换行符格式) - 调用
substring(text, 3, 0)→ 返回"hello\nworld\nhow\n"
已有的两种方案存在明显缺陷:
- 基于
string.lines()拼接:会频繁创建新String对象,性能损耗大 - 基于
indexOf定位换行符:无法兼容Unix(\n)、Windows(\r\n)、旧Mac(\r)等多种换行格式
问题1:获取原字符串中对应位置的索引x
要得到string.substring(0, x)中的x值,需要遍历原字符串并兼容所有换行符,核心逻辑和代码实现如下:
核心逻辑
- 初始化变量:当前行号
currentLine = 0,当前遍历位置pos = 0 - 逐字符遍历字符串:
- 若
currentLine等于目标行号line:计算当前行的末尾位置,返回pos + character和行末尾的较小值(避免字符位置超出当前行长度) - 若遇到换行符:
- 若当前字符是
\r且下一个字符是\n(Windows换行):pos加2,行号加1 - 否则(
\n或单独\r):pos加1,行号加1
- 若当前字符是
- 非换行符:
pos直接加1
- 若
- 边界处理:若目标行号超过总行数,返回整个字符串的长度
代码实现
public static int getTargetIndex(String text, int line, int character) { int currentLine = 0; int pos = 0; int len = text.length(); while (pos < len) { if (currentLine == line) { // 找到当前行的末尾位置 int lineEnd = pos; while (lineEnd < len) { char c = text.charAt(lineEnd); if (c == '\n' || c == '\r') { break; } lineEnd++; } // 返回字符位置和行末尾的较小值,避免越界 return Math.min(pos + character, lineEnd); } char c = text.charAt(pos); if (c == '\r') { // 处理Windows换行符\r\n if (pos + 1 < len && text.charAt(pos + 1) == '\n') { pos += 2; } else { pos += 1; } currentLine++; } else if (c == '\n') { // 处理Unix换行符\n pos += 1; currentLine++; } else { pos += 1; } } // 目标行超出总行数,返回整个字符串长度 return len; }
问题2:更优的子串截取方法
最优方案是原字符串直接遍历定位+原生substring截取,也就是结合上面的索引计算方法,直接调用text.substring(0, getTargetIndex(text, line, character))。
优势
- 性能最优:仅遍历一次字符串,无额外String对象创建或拼接,避免了
lines()流式处理的性能开销 - 全换行符兼容:支持
\n、\r\n、\r所有常见换行格式 - 边界处理完善:能处理行号超出、字符位置超出当前行长度等异常场景
完整方法实现
public static String substring(String text, int line, int character) { int targetIndex = getTargetIndex(text, line, character); return text.substring(0, targetIndex); }
内容的提问来源于stack exchange,提问作者amaidment
相关产品推荐
相关产品推荐

