You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
}

关键说明

  1. 拆分文本片段:通过isRTLChar方法识别波斯语和英语字符,将混合文本拆分为独立的RTL和LTR片段,每个片段单独创建Run。
  2. 单独设置Run方向:波斯语片段的Run设置Bidi=true,英语片段设置Bidi=false,避免互相干扰。
  3. 段落整体RTL:保证波斯语的整体排版对齐,同时LTR片段在RTL段落中会自动保持正确的显示顺序。

这样处理后,混合的波斯语和英语文本就能在生成的docx中正常显示,不会出现混乱。

内容的提问来源于stack exchange,提问作者nik ravan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 16:50:32