
本文讲解如何解析类似"000001bilbobagginsesq.1020"这样无分隔符的紧凑字符串,通过正则匹配提取字段,并用`printf`或`string.formatted()`实现对齐排版输出。
你遇到的问题本质并非printf失效,而是rec变量直接存储了原始未解析的整行字符串(如"000001BilboBagginsEsq.1020"),而printf("\n%4d %-60s ", line, rec)只是将整个长串按60字符左对齐打印——这当然无法产生你期望的“字段对齐”效果。
真正需要的是:先结构化解析字段,再分别格式化输出。由于原始数据无空格、逗号等分隔符,必须依赖字段的语义规律(如ID全数字、姓名首字母大写、年份结尾为数字等)进行正则切分。
以下是一个完整、健壮的解决方案:
✅ 步骤一:定义结构化数据类与解析逻辑
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Entry {
private final String id;
private final String firstName;
private final String lastName;
private final String title;
private final String birthYear;
// 使用正则精准捕获5个字段:ID(数字) + FirstName(大写开头单词) + LastName(同上) + Title(同上) + Year(数字)
private static final Pattern PATTERN = Pattern.compile(
"(\\d+)([A-Z][a-z._]+)([A-Z][a-z._]+)([A-Z][a-z._]+)(\\d+)"
);
public static Entry parse(String rawLine) {
Matcher m = PATTERN.matcher(rawLine);
if (!m.matches()) {
throw new IllegalArgumentException("Invalid format: " + rawLine);
}
return new Entry(
m.group(1), m.group(2), m.group(3), m.group(4), m.group(5)
);
}
private Entry(String id, String firstName, String lastName, String title, String birthYear) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.title = title;
this.birthYear = birthYear;
}
@Override
public String toString() {
// 每字段分配15字符宽度,左对齐;年份不加空格(右对齐更自然,此处保持左对齐一致性)
return String.format("%-15s%-15s%-15s%-15s%s",
id, firstName, lastName, title, birthYear);
}
}✅ 步骤二:在文件读取循环中解析并打印
// 假设 reader 已由 JFileChooser 初始化
int lineNum = 0;
String rec;
while ((rec = reader.readLine()) != null) {
lineNum++;
try {
Entry entry = Entry.parse(rec);
// 输出:行号 + 格式化后的字段(符合你的示例样式)
System.out.printf("%d %s%n", lineNum, entry);
} catch (IllegalArgumentException e) {
System.err.println("Parse error at line " + lineNum + ": " + e.getMessage());
}
}
System.out.println("\nData file read!");⚠️ 关键注意事项
- 正则可靠性:当前正则假设姓名/头衔均由“首字母大写+小写字母/点/下划线”组成(如 Bilbo, Baggins, Esq.)。若实际数据含空格、连字符(如 Mary-Jane)或小写前缀(如 de Gaulle),需扩展正则,例如 (\\d+)([A-Z][a-z._\\-]+)([A-Z][a-z._\\-]+)([A-Z][a-z._\\-]+)(\\d+)。
- 边界处理:reader.ready() 不是安全的循环条件(尤其对网络流或缓冲问题),应始终用 readLine() != null 判断。
- 资源管理:推荐使用 try-with-resources(如答案所示),避免手动 close() 遗漏导致文件句柄泄漏。
- 性能提示:Pattern.compile() 是开销操作,应定义为 static final,避免在循环内重复编译。
✅ 最终输出效果
输入行:000001BilboBagginsEsq.1020
输出:
1 000001 Bilbo Baggins Esq. 1020
完全匹配你的目标格式——字段间由空格对齐,视觉清晰,便于阅读与后续处理。
此方法将“原始字符串→结构化对象→格式化视图”的职责分离,既保证解析准确性,又赋予输出高度可控性,是处理无分隔符定长/变长记录的标准实践。









