spire.doc在word中生成公式

=依赖,需要在官网下载然后安装到maven中=

xml 复制代码
      <dependency>
            <groupId>e-iceblue</groupId>
            <artifactId>spire.doc.free</artifactId>
            <version>5.3.2</version>
        </dependency>

=这段代码可以替换word中的latex文本替换为latex公式=

java 复制代码
package com.kd.distributeSimulate.aiConversation.entity;

import com.spire.doc.*;
import com.spire.doc.documents.*;
import com.spire.doc.fields.*;
import com.spire.doc.fields.omath.*;

import java.util.regex.*;

public class LatexFormulaReplacer {

    public static void main(String[] args) {
        // 输入和输出文件路径
        String inputFilePath = "123.docx";
        String outputFilePath = "output_with_formulas.docx";
        
        // 加载Word文档
        Document doc = new Document();
        doc.loadFromFile(inputFilePath);
        
        // 处理文档中的所有LaTeX公式
        replaceLatexFormulas(doc);
        
        // 保存文档
        doc.saveToFile(outputFilePath, FileFormat.Docx);
        System.out.println("LaTeX公式替换完成!输出文件: " + outputFilePath);
    }
    private static void replaceLatexFormulasInTable(Table table,Document doc) {
        Pattern pattern = Pattern.compile("\\$(.*?)\\$");
        // 遍历表格的所有行
        for (Object rowObj : table.getRows()) {
            TableRow row = (TableRow) rowObj;

            // 遍历行中的所有单元格
            for (Object cellObj : row.getCells()) {
                TableCell cell = (TableCell) cellObj;

                // 处理单元格中的所有段落
                for (Object paragraphObj : cell.getParagraphs()) {
                    Paragraph paragraph = (Paragraph) paragraphObj;
                    String paragraphText = paragraph.getText();
                    Matcher matcher = pattern.matcher(paragraphText);

                    // 记录处理偏移量,因为替换后文本长度会变化
                    int offset = 0;

                    // 查找所有匹配的LaTeX公式
                    while (matcher.find()) {
                        // 计算实际位置(考虑之前的替换导致的偏移)
                        int startPos = matcher.start() - offset;
                        int endPos = matcher.end() - offset;
                        String fullMatch = matcher.group(0); // 包含$的完整匹配
                        String latexFormula = matcher.group(1); // 仅LaTeX内容

                        System.out.println("找到公式: " + latexFormula);

                        // 创建OfficeMath对象并设置LaTeX公式
                        OfficeMath math = new OfficeMath(doc);
                        math.fromLatexMathCode(latexFormula);

                        // 查找包含当前匹配文本的TextRange及其在段落中的索引
                        TextRangeInfo rangeInfo = findTextRangeWithPosition(paragraph, startPos, endPos);
                        if (rangeInfo == null) {
                            continue;
                        }

                        TextRange targetRange = rangeInfo.textRange;
                        int rangeIndex = rangeInfo.index;
                        int relativeStart = rangeInfo.relativeStart;
                        int relativeEnd = rangeInfo.relativeEnd;

                        // 拆分文本为三部分:公式前、公式、公式后
                        String textBefore = targetRange.getText().substring(0, relativeStart);
                        String textAfter = targetRange.getText().substring(relativeEnd);

                        // 移除原始文本范围
                        paragraph.getChildObjects().remove(targetRange);

                        // 插入公式前的文本(如果不为空)
                        if (!textBefore.isEmpty()) {
                            TextRange beforeRange = new TextRange(doc);
                            beforeRange.setText(textBefore);
                            paragraph.getChildObjects().insert(rangeIndex, beforeRange);
                            rangeIndex++; // 插入后索引增加,确保后续元素位置正确
                        }

                        // 插入公式对象
                        paragraph.getChildObjects().insert(rangeIndex, math);
                        rangeIndex++;

                        // 插入公式后的文本(如果不为空)
                        if (!textAfter.isEmpty()) {
                            TextRange afterRange = new TextRange(doc);
                            afterRange.setText(textAfter);
                            paragraph.getChildObjects().insert(rangeIndex, afterRange);
                        }

                        // 更新偏移量(原始长度 - 新内容长度,公式对象不占文本长度)
                        offset += fullMatch.length();
                    }
                }
            }
        }
    }
    /**
     * 替换文档中所有用$包裹的LaTeX文本为公式对象,保留前后文本
     * @param doc Word文档对象
     */
    public static void replaceLatexFormulas(Document doc) {
        // 正则表达式匹配$包裹的LaTeX公式(非贪婪模式)
        Pattern pattern = Pattern.compile("\\$(.*?)\\$");
        
        // 遍历所有节
        for (Object sectionObj : doc.getSections()) {
            Section section = (Section) sectionObj;
            // 处理节中的表格
            for (Object tableObj : section.getTables()) {
                Table table = (Table) tableObj;
                replaceLatexFormulasInTable(table,doc);
            }
            // 遍历所有段落
            for (Object paragraphObj : section.getParagraphs()) {
                Paragraph paragraph = (Paragraph) paragraphObj;
                
                // 获取段落文本
                String paragraphText = paragraph.getText();
                Matcher matcher = pattern.matcher(paragraphText);
                
                // 记录处理偏移量,因为替换后文本长度会变化
                int offset = 0;
                
                // 查找所有匹配的LaTeX公式
                while (matcher.find()) {
                    // 计算实际位置(考虑之前的替换导致的偏移)
                    int startPos = matcher.start() - offset;
                    int endPos = matcher.end() - offset;
                    String fullMatch = matcher.group(0); // 包含$的完整匹配
                    String latexFormula = matcher.group(1); // 仅LaTeX内容
                    
                    System.out.println("找到公式: " + latexFormula);

                    // 创建OfficeMath对象并设置LaTeX公式
                    OfficeMath math = new OfficeMath(doc);
                    math.fromLatexMathCode(latexFormula);
                    
                    // 查找包含当前匹配文本的TextRange及其在段落中的索引
                    TextRangeInfo rangeInfo = findTextRangeWithPosition(paragraph, startPos, endPos);
                    if (rangeInfo == null) {
                        continue;
                    }
                    
                    TextRange targetRange = rangeInfo.textRange;
                    int rangeIndex = rangeInfo.index;
                    int relativeStart = rangeInfo.relativeStart;
                    int relativeEnd = rangeInfo.relativeEnd;
                    
                    // 拆分文本为三部分:公式前、公式、公式后
                    String textBefore = targetRange.getText().substring(0, relativeStart);
                    String textAfter = targetRange.getText().substring(relativeEnd);
                    
                    // 移除原始文本范围
                    paragraph.getChildObjects().remove(targetRange);
                    
                    // 插入公式前的文本(如果不为空)
                    if (!textBefore.isEmpty()) {
                        TextRange beforeRange = new TextRange(doc);
                        beforeRange.setText(textBefore);
                        paragraph.getChildObjects().insert(rangeIndex, beforeRange);
                        rangeIndex++; // 插入后索引增加,确保后续元素位置正确
                    }
                    
                    // 插入公式对象
                    paragraph.getChildObjects().insert(rangeIndex, math);
                    rangeIndex++;
                    
                    // 插入公式后的文本(如果不为空)
                    if (!textAfter.isEmpty()) {
                        TextRange afterRange = new TextRange(doc);
                        afterRange.setText(textAfter);
                        paragraph.getChildObjects().insert(rangeIndex, afterRange);
                    }
                    
                    // 更新偏移量(原始长度 - 新内容长度,公式对象不占文本长度)
                    offset += fullMatch.length();
                }
            }
        }
    }
    
    /**
     * 辅助类:存储TextRange及其位置信息
     */
    private static class TextRangeInfo {
        TextRange textRange;
        int index; // 在段落子对象中的索引
        int relativeStart; // 在TextRange中的起始位置
        int relativeEnd; // 在TextRange中的结束位置
        
        TextRangeInfo(TextRange tr, int idx, int rs, int re) {
            textRange = tr;
            index = idx;
            relativeStart = rs;
            relativeEnd = re;
        }
    }
    
    /**
     * 在段落中查找包含指定位置范围的TextRange及其详细位置信息
     * @param paragraph 段落对象
     * @param startPos 起始位置(段落文本中的绝对位置)
     * @param endPos 结束位置(段落文本中的绝对位置)
     * @return 包含TextRange及位置信息的对象,未找到返回null
     */
    private static TextRangeInfo findTextRangeWithPosition(Paragraph paragraph, int startPos, int endPos) {
        int currentPos = 0;
        int childIndex = 0;
        
        for (Object obj : paragraph.getChildObjects()) {
            if (obj instanceof TextRange) {
                TextRange textRange = (TextRange) obj;
                String text = textRange.getText();
                int textLength = text.length();
                
                // 检查当前TextRange是否包含目标位置范围
                if (currentPos <= startPos && currentPos + textLength >= endPos) {
                    // 计算在当前TextRange中的相对位置
                    int relativeStart = startPos - currentPos;
                    int relativeEnd = endPos - currentPos;
                    
                    // 确保相对位置在有效范围内
                    if (relativeStart >= 0 && relativeEnd <= textLength) {
                        return new TextRangeInfo(textRange, childIndex, relativeStart, relativeEnd);
                    }
                }
                
                currentPos += textLength;
            }
            childIndex++;
        }
        
        return null;
    }
}
相关推荐
天远数科3 分钟前
Java数据工程:利用天远人车核验加强版优化智慧高速ETC发行合规体验
java·人工智能
.Bryce.4 分钟前
在智能体中使用A2A工具:让大模型自己决定“该找谁帮忙“
android·java·服务器·redis·后端·agent·a2a
xiaoqiMikko7 分钟前
fastjson 1.2.84 的补丁关掉了一个缓存:addAccept 包前缀白名单下,反序列化慢了 13~28 倍
java·后端·性能优化
XIAEE38 分钟前
转生到儿童编程异世界:我用 Vue 和 Scratch 建了一座 DREAM 学院
java·spring
XIAEE1 小时前
初次使用 Node + Koa + MongoDB 搭建服务器:从零到第一个 API
java·spring
m0_587383001 小时前
无人自助拼豆系统核心功能开发与部署落地全流程实战指南
java·经验分享·后端·struts·架构
雷一言说1 小时前
Spring AI 2.0:RAG 文档分块大小策略选择
java·spring
XIAEE1 小时前
Java 世界历险记:从一行 System.out.println 到整个 Spring 宇宙
java·spring
XIAEE1 小时前
微前端狂想曲:我试图让三个不同门派的前端住进同一栋楼
java·spring
XIAEE1 小时前
Linux 生存指南:从"终端恐惧症"到"命令行老司机"
java·spring