JAVA實現(xiàn)Excel和PDF上下標的操作代碼
1、簡介
最近項目需要實現(xiàn)26個小寫字母的上下標功能,自己去網(wǎng)上找了所有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軟件來造上下標,至于軟件可以去網(wǎng)上下載破解版,還有就是Unicode指定的數(shù)量就那么多,所以我們可以通過改變已有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ù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
三種SpringBoot中實現(xiàn)異步調用的方法總結
Spring Boot 提供了多種方式來實現(xiàn)異步任務,這篇文章主要為大家介紹了常用的三種實現(xiàn)方式,文中的示例代碼講解詳細,需要的可以參考一下2023-05-05
Spring Boot jar 啟動時設置環(huán)境參數(shù)的操作
這篇文章主要介紹了Spring Boot jar 啟動時設置環(huán)境參數(shù)的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06
springboot項目中application.properties無法變成小樹葉問題解決方案
這篇文章主要介紹了springboot項目中application.properties無法變成小樹葉問題解決,本文通過圖文實例代碼相結合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09
Java中遇到的For?input?string問題解決辦法
這篇文章主要給大家介紹了關于Java中遇到的For?input?string問題的解決辦法,如果出現(xiàn)這樣的異常報錯,是指的數(shù)據(jù)轉換時出錯,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2023-11-11
Spring Cloud學習教程之Zuul統(tǒng)一異常處理與回退
Spring Cloud Zuul對異常的處理整體來說還是比較方便的,流程也比較清晰,下面這篇文章主要給大家介紹了關于Spring Cloud學習教程之Zuul統(tǒng)一異常處理與回退的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧。2018-04-04
Java項目開發(fā)中實現(xiàn)分頁的三種方式總結
這篇文章主要給大家介紹了關于Java項目開發(fā)中實現(xiàn)分頁的三種方式,通過這一篇文章可以很快的學會java分頁功能,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下2022-02-02

