JAVA实现Excel和PDF上下标的操作代码
作者:拾荒的小海螺
1、简介
最近项目需要实现26个小写字母的上下标功能,自己去网上找了所有Unicode的上下标形式,缺少一些关键字母,顾后面考虑自己创建上下标字体样式,以此来记录。
2、Excel
Excel本身是支持上下标,我们可以通过Excel单元格的样式来设置当前字体上下标,因使用的是POI的maven包,这边就以POI的样例实现。
首先pom.xml引用:
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.9</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.9</version> </dependency>
实现上下标代码:
XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet("Sheet1"); XSSFRow row = sheet.createRow(0); XSSFCell cell = row.createCell(0); XSSFFont font = workbook.createFont(); font.setTypeOffset(XSSFFont.SS_SUB); // 上标 font.setTypeOffset(XSSFFont.SS_SUPER);//下标 XSSFRichTextString richTextString = new XSSFRichTextString("Hcu"); richTextString.applyFont(1, 2, font); // 设置第二个字符为上标 "c" richTextString.applyFont(2, 3, font); // 设置第三个字符为下标 "u" cell.setCellValue(richTextString); Path tempFile = Paths.get("E:\\dist\\pdf0.xlsx"); try(OutputStream os = Files.newOutputStream(tempFile)){ workbook.write(os); logger.error("xssfWorkbook-end:" + tempFile.toAbsolutePath()); }
3、造字
因某些字母没有对应的上下标字形,所以通过FontCreate软件来造上下标,至于软件可以去网上下载破解版,还有就是Unicode指定的数量就那么多,所以我们可以通过改变已有Unicode编码字符来作为我们上下标的编码。
可以通过找到当前分支少的Unicode字符做插入:比如选中西里尔字母这个分类点击 插入->字符:
然后我们对已有的字符做修改和做删除自己造:
最后形成我们自己所需要的字符:
4、PDF
生成的PDF,采用开源的是开放源码的站点sourceforge一个项目itextpdf,是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF或rtf的文档,而且可以将XML、Html文件转化为PDF文件。因项目通过Excel来转PDF,但是因itextpdf无法识别Excel上下标,并且缺少了关键上下标。
首先pom.xml引用:
<dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.10</version> </dependency>
输出中文,还要引入下面itext-asian.jar包:
<dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency>
通过以上造好的字母上下标,直接通过加载指定的Unicode来实现实现加载:
String value = "设计强度ƒ\u0460\u0461"; File pdfFile = new File("E:\\dist\\pdf1.pdf"); //字符和Unicode组合格式化 value = StringEscapeUtils.unescapeJava(value); Document document = new Document(); PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(pdfFile)); document.open(); // 将 Excel 单元格内容写入 PDF 文档 PdfPTable table = new PdfPTable(1); BaseFont bf = BaseFont.createFont("E:\\cell\\Merge.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); com.itextpdf.text.Font f = new com.itextpdf.text.Font(bf, 10); Paragraph p = new Paragraph(value, f); table.addCell(p); document.add(table); document.close(); writer.close();
5、字符映射
因设计可以通过造字来实现上下标字母,现在我们可以通过指定字符来实现当前上下标的标签替换,设计上下标通过标签来包裹,类似:下标:<sub> </sub> 上标:<sup><sup>来标签指定上下标。
通过解析当前字符串上下标标签来实现字符替换:
private static final String SUB_START = "<sub>"; //下标 private static final String SUB_END = "</sub>"; private static final String SUP_START = "<sup>"; //上标 private static final String SUP_END = "</sup>"; /** * 获取下一对标签的index,不存在这些标签就返回null * @param s * @param tag SUB_START或者SUP_START * @return int[]中有两个元素,第一个是开始标签的index,第二个元素是结束标签的index */ public static int[] getNextTagsIndex(String s, String tag) { int firstStart = s.indexOf(tag); if (firstStart > -1) { int firstEnd = 0; if (tag.equals(SUB_START)) { firstEnd = s.indexOf(SUB_END); String ssString = s.substring(firstStart, firstEnd+SUB_END.length()); if (ssString.contains(SUP_START)) { ssString = ssString.replace(SUP_START, "").replaceAll(SUP_END, ""); firstEnd = firstStart + ssString.indexOf(SUB_END); } }else if (tag.equals(SUP_START)) { firstEnd = s.indexOf(SUP_END); String ssString = s.substring(firstStart, firstEnd+SUP_END.length()); if (ssString.contains(SUB_START)) { ssString = ssString.replace(SUP_START, "").replaceAll(SUP_END, ""); firstEnd = firstStart + ssString.indexOf(SUP_END); } } if (firstEnd > firstStart) { return new int[] { firstStart, firstEnd }; } } return null; } /**移除下一对sub或者sup标签,返回移除后的字符串 * @param s * @param tag SUB_START或者SUP_START * @return */ public static String removeNextTags(String s, String tag) { s = s.replaceFirst(tag, ""); if (tag.equals(SUB_START)) { s = s.replaceFirst(SUB_END, ""); }else if (tag.equals(SUP_START)) { s = s.replaceFirst(SUP_END, ""); } return s; } /** * 判断是不是包含sub、sup标签 * @param s * @return */ public static boolean containTag(String s) { return (s.contains(SUB_START) && s.contains(SUB_END)) || (s.contains(SUP_START) && s.contains(SUP_END)); } /** * 处理字符串,得到每个sub、sup标签的开始和对应的结束的标签的index * @param s * @param tagIndexList 传一个新建的空list进来,方法结束的时候会存储好标签位置信息。 * <br>tagIndexList.get(0)存放的sub * <br>tagIndexList.get(1)存放的是sup * * @return 返回sub、sup处理完之后的字符串 */ public static String getIndexs(String s, List<List<int[]>> tagIndexList) { List<int[]> subs = Lists.newArrayList(); List<int[]> sups = Lists.newArrayList(); while (true) { int[] sub_pair = getNextTagsIndex(s, SUB_START); if (Objects.nonNull(sub_pair)) { int firstStart = sub_pair[0]; if (firstStart > -1) { int firstEnd = s.indexOf(SUB_END); String startString = s.substring(0, firstStart); String centreString = s.substring(firstStart, firstEnd); String endString = s.substring(firstEnd, s.length()); if (centreString.contains(SUP_START)) { centreString = centreString.replaceAll(SUP_START, "").replaceAll(SUP_END, ""); s = startString + centreString + endString; } } } int[] sup_pair = getNextTagsIndex(s, SUP_START); if (Objects.nonNull(sup_pair)) { int firstStart = sup_pair[0]; if (firstStart > -1) { int firstEnd = s.indexOf(SUP_END); String startString = s.substring(0, firstStart); String centreString = s.substring(firstStart, firstEnd); String endString = s.substring(firstEnd, s.length()); if (centreString.contains(SUB_START)) { centreString = centreString.replaceAll(SUB_START, "").replaceAll(SUB_END, ""); s = startString + centreString + endString; } } } boolean subFirst = false; boolean supFirst = false; List a = new ArrayList(); if (Objects.nonNull(sub_pair)) { a.add(sub_pair[0]); } if (Objects.nonNull(sup_pair)) { a.add(sup_pair[0]); } Collections.sort(a); if (Objects.nonNull(sub_pair)) { if (sub_pair[0] == Integer.parseInt(a.get(0).toString())) { subFirst = true; } } if (Objects.nonNull(sup_pair)) { if (sup_pair[0] == Integer.parseInt(a.get(0).toString())) { supFirst = true; } } if (sub_pair != null && subFirst) { s = removeNextTags(s, SUB_START); //<sub>标签被去掉之后,结束标签需要相应往前移动 sub_pair[1] = sub_pair[1] - SUB_START.length(); subs.add(sub_pair); continue; } if (sup_pair != null && supFirst) { s = removeNextTags(s, SUP_START); //<sup>标签被去掉之后,结束标签需要相应往前移动 sup_pair[1] = sup_pair[1] - SUP_START.length(); sups.add(sup_pair); continue; } if (sub_pair == null && sup_pair == null ) { break; } } tagIndexList.add(subs); tagIndexList.add(sups); return s; }
然后我们通过获取上下标标签的下标,来完成字符的替换,至于要替换的Unicode是存在哪里,这个自己设计。
首先我们要把指定的字符转成Unicode的:
unicode = StringEscapeUtils.unescapeJava(unicode);
然后通过全局的字符builder来重新构造字符串:
StringBuilder sb = new StringBuilder(value); unicode = StringEscapeUtils.unescapeJava(unicode); sb.replace(pair[0], pair[1], unicode);
到此这篇关于JAVA实现Excel和PDF上下标的文章就介绍到这了,更多相关JAVA Excel和PDF上下标内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!