JAVA實現(xiàn)Excel和PDF上下標的操作代碼
1、簡介
最近項目需要實現(xiàn)26個小寫字母的上下標功能,自己去網上找了所有Unicode的上下標形式,缺少一些關鍵字母,顧后面考慮自己創(chuàng)建上下標字體樣式,以此來記錄。
2、Excel
Excel本身是支持上下標,我們可以通過Excel單元格的樣式來設置當前字體上下標,因使用的是POI的maven包,這邊就以POI的樣例實現(xiàn)。
首先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>
實現(xiàn)上下標代碼:
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來實現(xiàn)實現(xiàn)加載:
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、字符映射
因設計可以通過造字來實現(xiàn)上下標字母,現(xiàn)在我們可以通過指定字符來實現(xiàn)當前上下標的標簽替換,設計上下標通過標簽來包裹,類似:下標:<sub> </sub> 上標:<sup><sup>來標簽指定上下標。
通過解析當前字符串上下標標簽來實現(xiàn)字符替換:
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實現(xiàn)Excel和PDF上下標的文章就介紹到這了,更多相關JAVA Excel和PDF上下標內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
將Swagger2文檔導出為HTML或markdown等格式離線閱讀解析
這篇文章主要介紹了將Swagger2文檔導出為HTML或markdown等格式離線閱讀,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-11-11Springboot實現(xiàn)Activemq死信隊列詳解
這篇文章主要介紹了Springboot實現(xiàn)Activemq死信隊列詳解,Activemq服務端配置重新投遞次數超過?MaximumRedeliveries?,則會進入死信隊列,默認情況,有一個死信隊列:AcitveMQ.DLQ,所有的消息都投遞到此隊列,包括過期消息,重投遞失敗消息,需要的朋友可以參考下2023-12-12@WebFilter在SpringBoot無效的原因分析和解決方案
使用Ruoyi的demo部署成功后,發(fā)現(xiàn)js、css等靜態(tài)文件都進入了過濾器,但是發(fā)現(xiàn)靜態(tài)文件沒有使用瀏覽器緩存,新建BrowserCacheFilter.java并增加@WebFilter處理,應用自動重啟后發(fā)現(xiàn)@WebFilter無效,所以本文給大家介紹了@WebFilter在SpringBoot無效的原因分析和解決方案2024-03-03