
本文讲解如何解析类似"000001bilbobagginsesq.1020"这样无分隔符的紧凑字符串,通过正则匹配提取字段,并用`printf`或`string.formatted()`实现对齐排版输出。
原始问题中,文件内容是连续拼接、无任何分隔符(如空格、逗号、制表符)的字符串,例如 "000001BilboBagginsEsq.1020"。直接调用 System.out.printf("%-60s", rec) 只是对整行做宽幅左对齐,无法自动拆分字段——这正是你看到 1 000001BilboBagginsEsq.1020 的原因:printf 并未“理解”字段边界,它只是把整个 rec 当作一个字符串处理。
要实现目标格式:
000001 Bilbo Baggins Esq. 1020
必须先结构化解析原始字符串,再按字段分别格式化。推荐使用 java.util.regex.Pattern 和 Matcher 进行稳健的字段提取。
✅ 正确步骤:解析 + 格式化
-
定义字段规则(基于示例数据推断):
- 字段1(ID):6位纯数字 → \\d{6}
- 字段2(First Name):首字母大写 + 小写字母/点/下划线 → [A-Z][a-z._]+
- 字段3(Last Name):同上
- 字段4(Title):同上(如 "Esq." 包含点)
- 字段5(Year):4位数字 → \\d{4}
编写解析类(推荐封装):
import java.util.regex.*;
class Entry {
String id, firstName, lastName, title, birthYear;
static Entry parse(String line) {
Entry e = new Entry();
// 精确匹配全部5个字段(避免过度匹配)
String regex = "(\\d{6})([A-Z][a-z._]+)([A-Z][a-z._]+)([A-Z][a-z._]+)(\\d{4})";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(line);
if (m.matches()) { // 使用 matches() 确保整行匹配,更安全
e.id = m.group(1);
e.firstName = m.group(2);
e.lastName = m.group(3);
e.title = m.group(4);
e.birthYear = m.group(5);
} else {
System.err.println("Warning: Line format mismatch — '" + line + "'");
}
return e;
}
@Override
public String toString() {
// 每字段预留15字符宽度,左对齐;年份右对齐更自然(可选)
return String.format("%-15s%-15s%-15s%-15s%-15s",
id, firstName, lastName, title, birthYear);
}
}? 提示:String.format() 或 String.formatted()(Java 15+)比链式 += 更高效、可读性更强;%-15s 表示左对齐、最小宽度15。
- 在文件读取循环中使用(注意资源管理与异常处理):
JFileChooser chooser = new JFileChooser();
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
int lineNumber = 0;
while ((line = reader.readLine()) != null) {
lineNumber++;
Entry entry = Entry.parse(line.trim()); // trim() 去除可能的首尾空白
System.out.printf("%-4d %s%n", lineNumber, entry); // 输出:行号 + 格式化记录
}
} catch (IOException e) {
System.err.println("读取文件失败: " + e.getMessage());
}
}
System.out.println("\nData file read!");⚠️ 注意事项与优化建议
- 正则健壮性:若实际数据存在变长(如 ID 不总是 6 位),应调整为 (\\d+) 并配合业务逻辑校验,而非硬编码 {6}。
- 大小写敏感:当前正则依赖 Bilbo/Baggins 首字母大写。若数据不规范(如全小写),需改用 (?i)[a-z] 或预处理标准化。
- 性能考虑:若文件极大,可将 Pattern.compile(regex) 提升为 static final Pattern,避免重复编译。
- 替代方案:若字段长度严格固定(如 ID=6, FirstName=10, LastName=12…),可用 substring() 切片,更快但缺乏容错性。
最终输出效果(含行号):
1 000001 Bilbo Baggins Esq. 1020 2 000002 Frodo Baggins Mr. 1050
通过结构化解析 + 字段级格式化,你就能精准控制每一列的宽度与对齐方式,彻底解决“printf 被忽略”的表象问题——本质不是 printf 失效,而是输入数据尚未被正确分解。










