Apache POI生成docx时波斯语-英语混排句子排版混乱问题求助
解决Apache POI生成含波斯语(法尔西语)与英语混合文本的docx排版混乱问题
问题核心是波斯语(RTL从右到左)和英语(LTR从左到右)混合时,统一设置段落Bidi或强制反转整个文本都会导致其中一种语言排版混乱。直接用cell.setText()会把所有文本塞进同一个Run,无法单独控制不同语言的方向,这是根本原因。
解决方案
放弃直接用setText()赋值,手动拆分混合文本中的RTL和LTR片段,给每个片段单独创建Run并设置对应的文本方向,同时段落整体保持RTL适配波斯语环境。
修改后的完整代码
public void WordTest(){ if (activites != null && !activites.isEmpty()) { try (XWPFDocument doc = new XWPFDocument()) { XWPFTable table = doc.createTable(); XWPFTableRow row1 = table.getRow(0); // 手动设置表头文本及RTL方向 setCellTextWithBidi(row1.getCell(0), "تاریخ", true); setCellTextWithBidi(row1.addNewTableCell(), "فعالیت", true); setCellTextWithBidi(row1.addNewTableCell(), "شماره", true); XWPFTableRow row2 = table.createRow(); String date = "1401-07-27"; String activity = "ماشین های مختلف مانند" + "BMW" + "و پیکان"; // 日期按RTL设置 setCellTextWithBidi(row2.getCell(0), date, true); // 处理混合语言文本 setMixedTextCell(row2.getCell(1), activity); // 数字按RTL设置 setCellTextWithBidi(row2.getCell(2), String.valueOf(1), true); // 设置列宽 table.getRow(0).getCell(0).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(1500)); table.getRow(0).getCell(1).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(6000)); table.getRow(0).getCell(2).getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(500)); // 设置表头背景色 for (XWPFTableCell cell : row1.getTableCells()) { cell.getCTTc().addNewTcPr().addNewShd().setFill("cccccc"); } String DEST = "./Reports/" + "filename" + "(" + cb_date.getSelectedItem().toString() + "-" + logeduser.getName() + ")" + ".docx"; // 保存文档 try (FileOutputStream out = new FileOutputStream(DEST)) { doc.write(out); } JOptionPane.showMessageDialog(null,"Report Created!"); } catch (IOException e) { e.printStackTrace(); } }else { JOptionPane.showMessageDialog(null,"The list is empty"); } } // 辅助方法:给单元格设置单一方向的文本 private void setCellTextWithBidi(XWPFTableCell cell, String text, boolean isRTL) { cell.removeParagraphs(); // 清空默认生成的段落 XWPFParagraph paragraph = cell.addParagraph(); XWPFRun run = paragraph.createRun(); run.setText(text); // 设置Run的文本方向 CTRPr rPr = run.getCTR().addNewRPr(); rPr.addNewBidi().setVal(isRTL); // 设置段落的文本方向,保证整体对齐 CTPPr pPr = paragraph.getCTP().addNewPPr(); pPr.addNewBidi().setVal(isRTL); } // 辅助方法:处理混合RTL和LTR的文本 private void setMixedTextCell(XWPFTableCell cell, String mixedText) { cell.removeParagraphs(); XWPFParagraph paragraph = cell.addParagraph(); // 段落整体设为RTL,适配波斯语的整体排版 CTPPr pPr = paragraph.getCTP().addNewPPr(); pPr.addNewBidi().setVal(true); int index = 0; int len = mixedText.length(); while (index < len) { // 提取连续的波斯语(RTL)字符片段 int start = index; while (start < len && isRTLChar(mixedText.charAt(start))) { start++; } if (start > index) { addRunWithBidi(paragraph, mixedText.substring(index, start), true); index = start; } // 提取连续的英语/数字(LTR)字符片段 start = index; while (start < len && !isRTLChar(mixedText.charAt(start))) { start++; } if (start > index) { addRunWithBidi(paragraph, mixedText.substring(index, start), false); index = start; } } } // 判断字符是否为波斯语(RTL)字符 private boolean isRTLChar(char c) { // 覆盖波斯语所在的Unicode范围 return (c >= '\u0600' && c <= '\u06FF') || (c >= '\u0750' && c <= '\u077F'); } // 添加指定方向的文本Run private void addRunWithBidi(XWPFParagraph paragraph, String text, boolean isRTL) { XWPFRun run = paragraph.createRun(); run.setText(text); CTRPr rPr = run.getCTR().addNewRPr(); rPr.addNewBidi().setVal(isRTL); }
关键说明
- 拆分文本片段:通过
isRTLChar方法识别波斯语和英语字符,将混合文本拆分为独立的RTL和LTR片段,每个片段单独创建Run。 - 单独设置Run方向:波斯语片段的Run设置
Bidi=true,英语片段设置Bidi=false,避免互相干扰。 - 段落整体RTL:保证波斯语的整体排版对齐,同时LTR片段在RTL段落中会自动保持正确的显示顺序。
这样处理后,混合的波斯语和英语文本就能在生成的docx中正常显示,不会出现混乱。
内容的提问来源于stack exchange,提问作者nik ravan
相关产品推荐
相关产品推荐

