本文详解如何使用 iText 5 将 Java 源文件(.java)转换为 PDF,并对 int、double、new 等保留字进行精准语法着色,避免 ANSI 转义符失效问题,兼顾词边界识别与行格式稳定性。
本文详解如何使用 itext 5 将 java 源文件(.java)转换为 pdf,并对 `int`、`double`、`new` 等保留字进行精准语法着色,避免 ansi 转义符失效问题,兼顾词边界识别与行格式稳定性。
在将 Java 源代码转为 PDF 的实际需求中(如自动生成带语法高亮的实验报告或教学材料),直接用 ANSI 颜色码(如 u001B[34m)标记字符串是无效的——PDF 不解析终端控制序列。正确方案是在 iText 渲染阶段按词粒度动态分配字体样式,即:逐词解析源码,对关键字使用蓝色加粗等特殊字体,其余文本保持常规 Courier 字体。
以下是一个健壮、可落地的实现方案,已适配 Java 关键字完整列表,并解决常见陷阱(如 double[] 中仅高亮 double、避免 do 误匹配 double、保留换行与空格结构):
✅ 核心思路
- 不依赖正则全局替换(易误匹配,如 "do" 匹配 "double");
- 采用语义感知分词:使用前瞻/后顾断言(lookahead/lookbehind)切分,确保 (、)、[、.、=、换行符、空格均为独立分界点;
- 关键字精确匹配:word.equals(keyword),杜绝子串误判;
- 字体复用优化:共用同一 BaseFont 实例,仅切换 Font 属性(大小、颜色、粗细)。
? 完整实现代码
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileOutputStream;
public class JavaToPdfHighlight {
// Java 8 完整关键字列表(含 strictfp, default 等)
private static final String JAVA_KEYWORDS =
"abstract,assert,boolean,break,byte,case,catch,char,class,const,continue," +
"default,do,double,else,enum,extends,final,finally,float,for,goto,if," +
"implements,import,instanceof,int,interface,long,native,new,package,privat," +
"protected,public,return,short,static,strictfp,super,switch,synchronized," +
"this,throw,throws,transient,try,void,volatile,while";
private static boolean isKeyword(String word) {
// 去除首尾空白,跳过空字符串和纯符号(如 "[", ")", ".")
word = word.trim();
if (word.isEmpty() || word.matches("[\[\]\(\)\{\}\.;,=+\-*/%&|^~!<>?:]")) {
return false;
}
String[] keywords = JAVA_KEYWORDS.split(",");
for (String kw : keywords) {
if (kw.equals(word)) return true;
}
return false;
}
public static void createPDF(String doc, String loc) {
try {
// 使用嵌入式等宽字体(推荐:Courier New 或 Consolas,此处用 Windows 默认 cour.ttf)
BaseFont fontBase = BaseFont.createFont(
"C:/Windows/Fonts/cour.ttf",
BaseFont.WINANSI,
BaseFont.EMBEDDED
);
Font fontRegular = new Font(fontBase, 13);
Font fontKeyword = new Font(fontBase, 13, Font.BOLD, new BaseColor(0, 0, 255)); // #0000FF
String targetLoc = loc.replace(".java", ".pdf");
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(targetLoc));
document.open();
// 高精度分词:在符号、空格、换行处切分,但保留其本身(零宽度断言)
String[] tokens = doc.split("(?=\[)|(?=\])|(?=\.)|(?=\()|(?=\))|(?=\{)|(?=\})|" +
"(?=;)|(?=,)|(?==)|(?<=\n)|(?=\n)|(?= )|(?<= )");
for (String token : tokens) {
Font usedFont = isKeyword(token) ? fontKeyword : fontRegular;
Chunk chunk = new Chunk(token, usedFont);
document.add(new Phrase(chunk));
}
document.close();
System.out.println("✅ PDF generated: " + targetLoc);
} catch (Exception e) {
e.printStackTrace();
}
}
}⚠️ 关键注意事项
- 字体路径需适配环境:cour.ttf 在 Linux/macOS 上不存在,建议改用 BaseFont.createFont(BaseFont.COURIER, ...) 或打包字体文件并用 getClass().getResourceAsStream() 加载;
- 换行处理:(?
- 性能提示:对超大文件(>10KB),建议改用 PdfContentByte 直接写入,避免 Phrase 频繁创建开销;
- 扩展性增强:可轻松扩展 isKeyword() 支持字符串字面量(绿色)、注释(灰色)、数字(橙色)等,只需增加对应 Chunk 分支与字体定义。
✅ 总结
本方案摒弃了脆弱的字符串替换逻辑,通过语义分词 + 精确关键字匹配 + 动态字体渲染三步,实现了专业级 Java 语法高亮 PDF 生成。它稳定支持所有 Java 关键字,规避子串误匹配,保留源码格式完整性,且代码简洁、易于维护与二次开发。对于教学、文档自动化、代码存档等场景,是 iText 5 下轻量高效的标准实践。










