精华内容
下载资源
问答
  • java解析word数学公式
    千次阅读
    2020-09-07 19:35:11

    公司正在做教育类产品,在遇到数学公式时,我们一般会使用latex表达式来做保存和渲染。
    在其中一个项目上,遇到一个需求是要从office文档(WordExcel)中导入题目内容至数据库,题目内容中就有可能包括数学公式,而在文档中编辑希望使用office的公式插件来写公式元素。
    其实公司之前的产品已经使用.net实现过此功能,不过现在公司全面转型Java,我们也要研究出一个适用Java的解决方案。

    office文档中的公式编辑器

    mathtype插件

    mathtype是一个第三方的数学公式插件,它能在Office文档中启用编辑,并生成一个带有公式矢量图的ole对象插入到文档中。
    原来.net的方案就是使用此种方式,使用mathtype提供的c#库包来解析ole对象,抽取LaTeX表达式。
    但在纯Java环境下就无法做到了。

    在楼主的不懈努力下,用谷歌谷到了一个解析Mathtype的工程,不过是go语言的

    可以直接使用转化ole为latex公式文本,亲测有效----关注博主私信发你

    https://download.csdn.net/download/qq_41536778/14156089

    office自带公式编辑器

    从2007版开始,Office也自带了一个公式编辑器。
    在2007版中WordExcel之间不同的是,前者插入的公式对象是Office MathML节点,后者插入的还是ole
    到了2010版开始,两个产品的公式编辑器插入的都是Office MathML节点了,但是两者对公式对象中的默认文字编码处理不同。
    这些不同点可以看出就算同样属于Office的产品,他们之间也是有很多不统一的地方。

    公式表达式

    LaTeX

    LaTeX是一种基于ΤΕΧ的排版系统,它非常适用于生成高印刷质量的科技和数学类文档。
    例如勾股定理用LaTeX表达:

     

    a^{2}+b^{2}=c^{2}
    

    常用的LaTeX渲染组件是MathJax
    我们在项目中使用的便是LaTeX,所以本次研究就是如何将Office中的公式对象转换成LaTeX表达式。

    Mathml

    全称为数学标记语言(Mathematical Markup Language),是一种基于XML的标准,用来在互联网上书写数学符号和公式的置标语言。
    例如一个表达式:

     

    <math xmlns="http://www.w3.org/1998/Math/MathML">
        <msup>
            <mi>n</mi>
        <mrow>
          <mi>p</mi>
          <mo>-</mo>
              <mn>1</mn>
        </mrow>
      </msup>
      <mspace width=".2em"/>
      <mo>≡</mo>
      <mspace width=".2em"/>
      <mn>1</mn>
      <mspace width=".2em"/>
      <mo>(</mo>
      <mi>mod</mi>
      <mspace width=".2em"/>
      <mi>p</mi>
      <mo>)</mo>
    </math>
    

    Office MathML (OMML)

    office2007之后版本所编辑的公式对象便是OMMLOMMLoffice为了配合Office Open Xml制定的数学标记语言。
    例如:

     

    <m:oMathPara><!-- mathematical block container used as a paragraph -->
      <m:oMath><!-- mathematical inline formula -->
        <m:f><!-- a fraction -->
          <m:num><m:r><m:t>π</m:t></m:r></m:num><!-- numerator containing a single run of text -->
          <m:den><m:r><m:t>2</m:t></m:r></m:den><!-- denominator containing a single run of text -->
        </m:f>
      </m:oMath>
    </m:oMathPara>
    

    转换关系

    我们在项目中使用到的三者之间转换关系是:OMML -> MathML -> LaTex
    Office在安装目录中提供了将OMML转为MathMLxsl工具:MML2OMML.XSL
    MathMLLaTex使用网上找到另一个xsl工具mmltex.xsl

    Office文档Java解析

    2007与之前的版本

    用过一段Office的同学们都知道,Office文档分为wordwordx这两种类型,分别对应着2007之前与之后的版本格式。
    2007之前版本使用的Office文档是二进制文件。而之后版本中x代表的意义是xml,表明新版的Office文档使用Office Open Xml规范定义文件格式。
    如果我们把wordx文件的扩展名改为zip,就可以正常解压出Word文档包含的所有内容。

    POI

    相信用Java做过信息系统的同学都遇过生成统计Excel文档或解析Excel导入数据的功能。这时我们最常使用的开发库就是Apache POI
    POI支持二进制与Office Open Xml文档,可以满足我们大部分的Office文档解析需求。

    解析公式实例

    首先要说明我们的功能限制:只针对Office2010及以上的Office Open Xml文档,WordExcel均可。 其中,Excel的公式数学字符需要转为普通字符,否则会出现Java无法识别的字符。
    这里用Excel文档为例子来说明解析过程。

    功能实现思路

    这个功能的关键点在于如何获得Office文档中的公式节点(OMML),得到OMML后我们就可以使用上述的两个工具转换为LaTeX

    获得OMML

    既然我们知道Excel文档是一个xml,那只需要使用xml解析工具读出OMML节点就行了。
    先用POI得到操作的XSSFSheet

     

    String basePath = "f:\\";
    FileInputStream fis = new FileInputStream(basePath + "math.xlsx");
    OPCPackage pack = OPCPackage.open(fis);
    XSSFWorkbook workbook = new XSSFWorkbook(pack);
    XSSFSheet sheet = workbook.getSheetAt(0);
    

    插入在Excel文档中的图片、公式及其他元素,它都是存放在一个叫drawing的单独xml文件中,其中的节点记录了元素摆放的位置信息。用POI得到drawing元素:

     

    XSSFDrawing dr = sheet.getDrawingPatriarch();
    CTDrawing drawing = dr.getCTDrawing();
    CTOneCellAnchor[] oneCells = drawing.getOneCellAnchorArray();   //所有的图片、公式等元素
    

    每个CTOneCellAnchorxml里包含元素的位置信息,包括X坐标、Y坐标,所在行、所在列等,更重要的是图片或公式的描述节点。OMML节点名为m:oMathPara,这里我们就使用dom4jxpath来获得OMML

     

    CTOneCellAnchor c = oneCells[0];
    String xml = c.xmlText();   //得到xml串
    
    //dom4j解析器的初始化
    SAXReader reader = reader = new SAXReader(new DocumentFactory());
    Map<String, String> map=new HashMap<String, String>();
    map.put("xdr","http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing");
    map.put("m","http://schemas.openxmlformats.org/officeDocument/2006/math");
    reader.getDocumentFactory().setXPathNamespaceURIs(map); //xml文档的namespace设置
    
    InputSource source = new InputSource(new StringReader(xml));
    source.setEncoding("utf-8");
    Document doc = reader.read(source);
    Element root = doc.getRootElement();
    Element e = (Element)root.selectSingleNode("//m:oMathPara");    //用xpath得到OMML节点
    String omml = e.asXML();    //转为xml
    

    转换OMML为Mathml及LaTeX

    顺利得到OMML后,就可以使用xsl转换工具得到MathmlLaTeX了。
    这里先写一下xsl转换工具方法,使用javax.xml.transform工具包实现:

     

    /**    
     * <p>Description: xsl转换器</p>
     */
    public static String xslConvert(String s, String xslpath, URIResolver uriResolver){
        TransformerFactory tFac = TransformerFactory.newInstance();
        if(uriResolver != null)  tFac.setURIResolver(uriResolver);
        StreamSource xslSource = new StreamSource(MathmlUtils.class.getResourceAsStream(xslpath));
        StringWriter writer = new StringWriter();   
        try {
            Transformer t = tFac.newTransformer(xslSource);
            Source source = new StreamSource(new StringReader(s));
            Result result = new StreamResult(writer);   
            t.transform(source, result);
        } catch (TransformerException e) {
            logger.error(e.getMessage(), e);
        }
        return writer.getBuffer().toString();
    }
    
    /**
     * <p>Description: 将mathml转为latx </p>
     * @param mml
     * @return
     */
    public static String convertMML2Latex(String mml){
        mml = mml.substring(mml.indexOf("?>")+2, mml.length()); //去掉xml的头节点
        URIResolver r = new URIResolver(){  //设置xls依赖文件的路径
            @Override
            public Source resolve(String href, String base) throws TransformerException {
                InputStream inputStream = MathmlUtils.class.getResourceAsStream("/conventer/mml2tex/" + href);
                return new StreamSource(inputStream);
            }
        };
        String latex = xslConvert(mml, "/conventer/mml2tex/mmltex.xsl", r);
        if(latex != null && latex.length() > 1){
            latex = latex.substring(1, latex.length() - 1);
        }
        return latex;
    }
    
    /**
     * <p>Description: office mathml转为mml </p>
     * @param xml
     * @return
     */
    public static String convertOMML2MML(String xml){
        String result = xslConvert(xml, "/conventer/OMML2MML.XSL", null);
        return result;
    }
    

    至此我们就可以将OMML转成MathmlLaTeX表达式了:

     

    String mml = convertOMML2MML(omml);
    String latex = convertMML2Latex(mml);
    

    一些心得体会

    实现这个功能的时候,手上真的也没太多直接的资料可以参考,走过好几个弯路,网上查到的信息很多也是过时或者把话说一半的。
    在与同事的交流下,使用不同思路,查阅许多api文档,再加上不断的尝试,也算完成了这个不算实用的功能。
    就算你自己本身不够优秀,在一个好的团队也能不断推着你向前走。一个人最终能前行到多远,还是要看与你同行的人。

    更多相关内容
  • java解析office数学公式

    2021-05-08 11:13:22
    公司的项目遇到一个需求是从office word中导入数据回显到页面当中,里面穿插着一些数学公式,又不想使用图片的方式存储数学公式。所以敲定了将公式转换成latex表达式,然后前端使用MathJax渲染出数学公式的方案。 ...

    一、概述

    公司的项目遇到一个需求是从office word中导入数据回显到页面当中,里面穿插着一些数学公式,又不想使用图片的方式存储数学公式。所以敲定了将公式转换成latex表达式,然后前端使用MathJax渲染出数学公式的方案。

    1.1 所需资源

    名称地址描述
    mmltx.xslhttps://sourceforge.net/projects/xsltml/files/xsltml/MathML转LaTex工具
    MML2OMML.XSLhttps://download.csdn.net/download/han949417140/18465121OMML转为MathML的xsl工具

    1.2 office文档中的公式编辑器

    • office自带公式编辑器
      从2007版开始,Office也自带了一个公式编辑器。
      在2007版中Word与Excel之间不同的是,前者插入的公式对象是Office MathML节点,后者插入的还是ole。
      到了2010版开始,两个产品的公式编辑器插入的都是Office MathML节点了,但是两者对公式对象中的默认文字编码处理不同。
      这些不同点可以看出就算同样属于Office的产品,他们之间也是有很多不统一的地方。

    • 公式表达式
      LaTeX
      LaTeX是一种基于ΤΕΧ的排版系统,它非常适用于生成高印刷质量的科技和数学类文档。
      例如勾股定理用LaTeX表达:
      a 2 + b 2 = c 2 {a}^{2}+{b}^{2}={c}^{2} a2+b2=c2
      常用的LaTeX渲染组件是MathJax,
      vue渲染教程请参考:http://www.manongjc.com/detail/11-pwanxyhkqeiokqi.html
      我们在项目中使用的便是LaTeX,所以本次研究就是如何将Office中的公式对象转换成LaTeX表达式。

    • Mathml
      全称为数学标记语言(Mathematical Markup Language),是一种基于XML的标准,用来在互联网上书写数学符号和公式的置标语言。

    • Office MathML (OMML)
      在office2007之后版本所编辑的公式对象便是OMML。OMML是office为了配合Office Open Xml制定的数学标记语言。

    1.3 转换关系

    我们在项目中使用到的三者之间转换关系是:OMML -> MathML -> LaTex
    Office在安装目录中提供了将OMML转为MathML的xsl工具:MML2OMML.XSL
    MathML转LaTex使用网上找到另一个xsl工具mmltex.xsl

    二、代码实现office公式解析

    首先要说明我们的功能限制:只针对Office2011及以上的Office Open Xml文档,Word和Excel均可。
    这里用Word文档为例子来说明解析过程。

    2.1 引入pom包

    pom…xml引入office接续所需jar

    <dependency>
                <groupId>cn.afterturn</groupId>
                <artifactId>easypoi-spring-boot-starter</artifactId>
                <version>4.2.0</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.apache.poi</groupId>
                        <artifactId>poi</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.apache.poi</groupId>
                        <artifactId>poi-ooxml</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.apache.poi</groupId>
                        <artifactId>poi-ooxml-schemas</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas -->
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml-schemas</artifactId>
                <version>4.0.0</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>4.0.0</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.apache.poi/ooxml-schemas -->
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>ooxml-schemas</artifactId>
                <version>1.4</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
            <dependency>
                <groupId>dom4j</groupId>
                <artifactId>dom4j</artifactId>
                <version>1.6.1</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/jaxen/jaxen -->
            <dependency>
                <groupId>jaxen</groupId>
                <artifactId>jaxen</artifactId>
                <version>1.1.6</version>
            </dependency>
    

    2.2 导入解析所需工具

    将上面下载的资源文件拷贝到项目resources/conventer下,如图:
    在这里插入图片描述

    2.3 编写代码解析office公式

    package com.hanergy.out.utils;
    
    import lombok.extern.slf4j.Slf4j;
    import org.apache.poi.xwpf.usermodel.*;
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
    import org.springframework.web.multipart.MultipartFile;
    
    
    import javax.xml.transform.*;
    import javax.xml.transform.stream.StreamResult;
    import javax.xml.transform.stream.StreamSource;
    import java.io.*;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    
    /**
     * word内容段落、公式xml标签
     * 正常文本:
     * <w:r> 标签对应一个 XWPFRun对象
     * <w:t xml:space=“preserve”> 标签对应一段在 Word中的字符(也可以是一个字符)
     * 公式:
     * <w:object> 标签对应一个公式(当然我们这里只讲公式,此标签中也可以是一个 Excel也可以是一个 PPT等等)
     * <v:shape> 标签中有个 style属性,这里 style就是图片在 Word中显示的宽高
     * <v:imagedata> 标签关联着显示的图片( <v:imagedata>为 <v:shape>子标签)
     * <o:OLEObject>标签关联着图片显示公式对应的二进制文件(二进制文件也是最重要的文件,没有这个文件当你在word中双击时,是打不开第三方公式插件的)
     *
     */
    /**
     * @description:
     * @author: Han LiDong
     * @create: 2021/5/7 10:33
     * @update: 2021/5/7 10:33
     */
    @Slf4j
    public class WordUtil {
    
        public static void main(String[] args) throws Exception {
    //        MultipartFile file = null;
    //        InputStream inputStream = file.getInputStream();
            // 所有公式latex表达式集合,借助mathJax可以在页面上进行展示
            List <String> formulas = getFormulaMap(new FileInputStream("C:\\D\\算法-β系数.docx"));
            log.info("解析到{}个公式",formulas.size());
            // word解析 公式+文本
            wordAnalysis(new FileInputStream("C:\\D\\算法-β系数.docx"));
        }
    
    }
    
        /**
         * word所有内容解析(公式、文本)
         * @param inputStream
         * @throws Exception
         */
        public static void wordAnalysis(InputStream inputStream) throws Exception {
            XWPFDocument word = new XWPFDocument(inputStream);
            try {
                for (IBodyElement ibodyelement : word.getBodyElements()) {
                    if (ibodyelement.getElementType().equals(BodyElementType.PARAGRAPH)) {  //段落
                        XWPFParagraph paragraph = (XWPFParagraph) ibodyelement;
                        //段落解析
                        String paragraphStr = parseParagraph(paragraph);
                    } else if (ibodyelement.getElementType().equals(BodyElementType.TABLE)) {   //表格
                        XWPFTable table = (XWPFTable) ibodyelement;
                        for (XWPFTableRow row : table.getRows()) {  //行
                            for (XWPFTableCell cell : row.getTableCells()) {    //cell
                                List<String> cellMath = new ArrayList<>(16);
                                for (XWPFParagraph paragraph : cell.getParagraphs()) {  //段落
                                    //cell段落解析
                                    String paragraphStr = parseParagraph(paragraph);
                                    if (!"".equals(paragraphStr.trim())){
                                        cellMath.add(paragraphStr);
                                    }
                                }
                                log.info("当前cell有{}个公式",cellMath.size());
                            }
                        }
                    }
                }
    
            } finally {
                word.close();
            }
        }
    
    
        /**
         * 解析word中公式(转换成latex表达式)
         *
         * @param inputStream  文件流
         * @return
         */
        public static List<String> getFormulaMap(InputStream inputStream) throws IOException, DocumentException {
            //XWPFDocument xwpfDocument = new XWPFDocument(inputStream);
            Map<Integer, String> result = new HashMap<>();
            XWPFDocument word = new XWPFDocument(inputStream);
            //storing the found MathML in a AllayList of strings
            List<String> mathMLList = new ArrayList<String>(16);
            try {
                for (IBodyElement ibodyelement : word.getBodyElements()) {
                    if (ibodyelement.getElementType().equals(BodyElementType.PARAGRAPH)) {  //段落
                        XWPFParagraph paragraph = (XWPFParagraph) ibodyelement;
                        //段落解析
                        List<String> mathList = parseMathParagraph(paragraph);
                        mathMLList.addAll(mathList);
                    } else if (ibodyelement.getElementType().equals(BodyElementType.TABLE)) { //woed表格
                        XWPFTable table = (XWPFTable) ibodyelement;
                        for (XWPFTableRow row : table.getRows()) {
                            for (XWPFTableCell cell : row.getTableCells()) {
                                List<String> cellMath = new ArrayList<>(16);
                                for (XWPFParagraph paragraph : cell.getParagraphs()) {
                                    //cell段落解析
                                    List<String> mathList = parseMathParagraph(paragraph);
                                    mathMLList.addAll(mathList);
                                    //cellMath.addAll(mathList);
                                }
                            }
                        }
                    }
                }
            } finally {
                word.close();
            }
            log.info("当前文档一共有{}个公式",mathMLList.size());
            return mathMLList;
        }
    
        /**
         * 公式段落解析
         * @param xwpfParagraph
         * @throws DocumentException
         */
        public static List<String> parseMathParagraph(XWPFParagraph xwpfParagraph) throws DocumentException {
            CTP ctp = xwpfParagraph.getCTP();
            String xmlText = ctp.xmlText();
            List<String > mathList = new ArrayList<>();
            if (xmlText.contains("<m:oMath>")) {
                //得到根节点的值
                SAXReader saxReader = new SAXReader();
                //将String类型的字符串转换成XML文本对象
                Document doc = saxReader.read(new ByteArrayInputStream(xmlText.getBytes()));
                Element root = doc.getRootElement();
                // 一个段落多个表达式解析
                List<Element> omMaths = root.selectNodes("//m:oMath");    //用xpath得到OMML节点
                for (Element ele : omMaths) {
                    /**
                     * OMML -> MathML -> LaTex
                     * Office在安装目录中提供了将OMML转为MathML的xsl工具:MML2OMML.XSL
                     * MathML转LaTex使用网上找到另一个xsl工具mmltex.xsl。
                     */
                    String xml = ele.asXML();
                    //xml转 mathml
                    String mml = convertOMML2MML(xml);
                    //mathml转latx
                    String latex = convertMML2Latex(mml);
                    mathList.add(latex);
                    log.info("late表达式:{}" , latex);
                }
            }
            return mathList;
        }
    
        /**
         * 段落解析
         * @param xwpfParagraph
         * @throws DocumentException
         */
        public static String parseParagraph(XWPFParagraph xwpfParagraph) throws DocumentException {
            CTP ctp = xwpfParagraph.getCTP();
            String xmlText = ctp.xmlText();
            StringBuilder sb = new StringBuilder();
    //        if (xmlText.contains("<m:oMath>")) {
    
            //段落文本内容
            sb.append(xwpfParagraph.getParagraphText());
            //段落公式解析
            //得到根节点的值
            SAXReader saxReader = new SAXReader();
            //将String类型的字符串转换成XML文本对象
            Document doc = saxReader.read(new ByteArrayInputStream(xmlText.getBytes()));
            Element root = doc.getRootElement();
            // 一个段落多个表达式解析
            List<Element> omMaths = root.selectNodes("//m:oMath");    //用xpath得到OMML节点
            if (omMaths != null && !omMaths.isEmpty()) {
                for (Element ele : omMaths) {
                    /**
                     * OMML -> MathML -> LaTex
                     * Office在安装目录中提供了将OMML转为MathML的xsl工具:MML2OMML.XSL
                     * MathML转LaTex使用网上找到另一个xsl工具mmltex.xsl。
                     */
                    String xml = ele.asXML();
                    //xml转 mathml
                    String mathml = convertOMML2MML(xml);
                    //mathml转latx
                    String latex = convertMML2Latex(mathml);
                    sb.append(latex);
                    log.info("latex表达式:{}",latex);
                }
            }
            log.info("公式个数:{},解析内容:{}",omMaths.size(),sb.toString());
            return sb.toString();
        }
    
        /**
         * Description: xsl转换器</p>
         * @param s  公式xml字符串
         * @param xslpath   转换器路径
         * @param uriResolver xls依赖文件
         * @return
         */
        public static String xslConvert(String s, String xslpath, URIResolver uriResolver){
            TransformerFactory tFac = TransformerFactory.newInstance();
            if(uriResolver != null) {
                tFac.setURIResolver(uriResolver);
            }
            StreamSource xslSource = new StreamSource(WordUtil.class.getResourceAsStream(xslpath));
            StringWriter writer = new StringWriter();
            try {
                Transformer t = tFac.newTransformer(xslSource);
                Source source = new StreamSource(new StringReader(s));
                Result result = new StreamResult(writer);
                t.transform(source, result);
            } catch (TransformerException e) {
                log.error(e.getMessage(), e);
            }
            return writer.getBuffer().toString();
        }
    
        /**
         * <p>Description: 将mathml转为latx </p>
         * @param mml mathml字符串
         * @return
         */
        public static String convertMML2Latex(String mml){
            mml = mml.substring(mml.indexOf("?>")+2, mml.length()); //去掉xml的头节点
            URIResolver r = new URIResolver(){  //设置xls依赖文件的路径
                @Override
                public Source resolve(String href, String base) throws TransformerException {
                    File f = new File("/conventer/mml2tex/" + href);
                    InputStream inputStream = WordUtil.class.getResourceAsStream("/conventer/mml2tex/" + href);
                    return new StreamSource(inputStream);
                }
            };
            String latex = xslConvert(mml, "/conventer/mml2tex/mmltex.xsl", r);
            if(latex != null && latex.length() > 1){
                latex = latex.substring(1, latex.length() - 1);
            }
            return latex;
        }
        /**
         * <p>Description: office xml转为mathml </p>
         * @param xml  公式xml
         * @return
         */
        public static String convertOMML2MML(String xml){
            // 进行转换的过程中需要借助这个文件,一般来说本机安装office就会有这个文件,找到就可以
            String result = xslConvert(xml, "/conventer/OMML2MML.XSL", null);
            return result;
        }
    
    • 最终运行结果如图:

    在这里插入图片描述

    • word文档示例
      在这里插入图片描述
    • 在线解析latex表达式
      从程序运行果果中拷贝一个latex表达式在线解析:x=\frac{-b\pm \sqrt{{b}^{2}-4ac}}{2a}
      在线解析网址:https://latex.91maths.com/

    在这里插入图片描述

    参考博客:
    https://blog.csdn.net/qq_41536778/article/details/108454415
    https://www.cnblogs.com/wadmwz/p/10460033.html

    展开全文
  • java解析数学公式

    2014-11-27 11:31:12
    这个是我自己开发的用java编写的解析简单数学公式的jar, 资源下载积分有点贵,但很值得。 解析的公式可以为:+,-,*,/,max() min(),以及带()的 公式例如: 344+(344-(34+3434)/90)*45 344.34*2+343.34/3 max...
  • 里面包含图片转码的jar包,项目中使用的
  • java word 导出数学公式latex、katex与图片自适应需求技术问题解决技术问题 需求 公司之前在做导出数学试卷的时候使用网页的方式生成试卷(零时解决方案),通过网页的打印pdf方式来生成试卷,使用网页生成试卷在...

    java word 导出数学公式latex、katex与图片自适应

    需求

    公司之前在做导出数学试卷的时候使用网页的方式生成试卷(零时解决方案),通过网页的打印pdf方式来生成试卷,使用网页生成试卷在通过浏览器的打印转成pdf存在一些缺陷,网页上布局使用相对和绝对定位处理,会存在图片太大显示不全的问题、公式无法自动换行的问题,页面样式转pdf后无法保证pdf样式的完整性。试卷太多的时候不同学生的试卷不同,使用自动化脚本转pdf根本不适用,费时费力而且无法保证试卷的样式,打印成纸质的问题太多,因此迫切需要将所有学生的试卷一键下载成zip包:
    这里补充一下,为什么不直接转pdf,主要是个人未找到latex在pdf中如何显示的问题,如果数学公式转存图片然后放pdf中又会存在公式图片太长超过pdf宽度导致公式线上不全的问题

    实现效果

    在这里插入图片描述

    技术问题

    要完成数学试卷一键下载成zip包,需要解决几个技术问题
    1、 latex、katex 转word 的数学公式标准
    2、 试卷中图片大小、格式问题等比例缩放问题
    3、 导出的性能问题
    4、word版本,(我这里使用的word2019),200个学生60秒完成导出

    解决技术问题

    1、首先latex katex数学公式转word公式标准omml,之前了解过latex转图片,或者使用mathml标准在浏览器显示然后通过html转pdf或者word ,主要是因数学公式在网页上线上使用mathjax 处理,在java上没有找到办法在java中加载代码,当然个人尝试过使用javax.script.ScriptEngine 去执行js代码来处理,ScriptEngine 无法获取到doment对象,因此放弃了使用html 转word或pdf的方案 。采用fmath包与 latex_toword包 直接转omml,这两个包经过测试部分公式无法转换成功,
    2、目前采用的方案是先将latex转mathml转omml、latex转mathml使用fmath转出来的mathml1.0标准,因此在转omml转出的公式无法在word显示或者导致word报错,word无法打开等问题。因此放弃使用fmath,经过大量的实现找替代方案终于找到
    3、mathml 转omml ,通过xsl 执行转换

     <dependency>
    			<groupId>com.thoughtworks.xstream</groupId>
    			<artifactId>xstream</artifactId>
    			<version>1.4.11.1</version>
    			<scope>compile</scope>
    		</dependency>
    

    可以完美解决
    /**
    * latex 转 mathml
    * @param latex
    * @return mathml
    * @throws IOException
    /
    public String toMath(String latex) throws IOException {
    SnuggleEngine engine = new SnuggleEngine();
    SnuggleSession session = engine.createSession();
    /
    加载、存储、操作和处理MathML XML文档的API。 */
    SnuggleInput input = new SnuggleInput(latex);
    session.parseInput(input);
    String xmlString = session.buildXMLString();
    return xmlString;
    }

    /**
       *  mathml 转omml
        * xml:是解析的内容
        */
       @SneakyThrows
       public static String xslConvert(String xml) throws FileNotFoundException {
       	TransformerFactory tFac = TransformerFactory.newInstance();
       	StringWriter writer = new StringWriter();
       	StringBuffer stringBuilder=new StringBuffer();
       	try {
       		Transformer t = tFac.newTransformer(new StreamSource(new StringReader(xslString)));
       		Source source = new StreamSource(new StringReader(xml));
       		Result result = new StreamResult(writer);
       		t.transform(source, result);
       		stringBuilder.append(writer.getBuffer().toString());
       	} catch (TransformerException e) {
       		//stringBuilder.append("公式转换出错");
       		e.printStackTrace();
       	} finally {
       		if(writer!=null){
       			writer.close();
       		}
       	}
       	return stringBuilder.toString();
       }
       ```
       今天就先写到这儿。
    
    
    
    
    
    
    
    
    
    展开全文
  • package ...import java.io.BufferedWriter;import java.io.ByteArrayOutputStream;import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; impo...
    package com.wcpdoc.exam.exam.utils;


    import java.io.BufferedWriter;
    import java.io.ByteArrayOutputStream;
    import java.io.File;  
    import java.io.FileInputStream;  
    import java.io.FileNotFoundException;  
    import java.io.FileOutputStream;  
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;  
    import java.io.OutputStreamWriter;  
    import java.io.PrintWriter;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import java.util.zip.GZIPOutputStream;


    import javax.xml.transform.OutputKeys;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.TransformerFactory;
    import javax.xml.transform.dom.DOMSource;
    import javax.xml.transform.stream.StreamResult;


    import org.apache.commons.lang.StringUtils;
    import org.apache.poi.hwpf.HWPFDocument;  
    import org.apache.poi.hwpf.model.PicturesTable;  
    import org.apache.poi.hwpf.usermodel.CharacterRun;  
    import org.apache.poi.hwpf.usermodel.Picture;  
    import org.apache.poi.hwpf.usermodel.Range;  
    import org.apache.poi.hwpf.usermodel.Paragraph;     
    import org.apache.poi.hwpf.usermodel.Table;     
    import org.apache.poi.hwpf.usermodel.TableCell;     
    import org.apache.poi.hwpf.usermodel.TableIterator;     
    import org.apache.poi.hwpf.usermodel.TableRow;
    import org.w3c.dom.Document;


    import com.wcpdoc.exam.exam.entity.Question;


    import net.arnx.wmf2svg.gdi.svg.SvgGdi;
    import net.arnx.wmf2svg.gdi.wmf.WmfParser;  




    /**
     *


     * @Description:Word试卷文档模型化解析


     * @author <a href="mailto:thoslbt@163.com">Thos</a> 42  * @ClassName: WordToHtml 44  * @version V1.0
     *
     */
    public class WordUtils {


        /**
         * 回车符ASCII码
         */
        private static final short ENTER_ASCII = 13;


        /**
         * 空格符ASCII码
         */
        private static final short SPACE_ASCII = 32;


        /**
         * 水平制表符ASCII码
         */
        private static final short TABULATION_ASCII = 9;


        public static String htmlText = "";
        public static String htmlTextTbl = "";
        public static int counter=0;
        public static int beginPosi=0;
        public static int endPosi=0;
        public static int beginArray[];
        public static int endArray[];
        public static String htmlTextArray[];
        public static boolean tblExist=false;


        public static final String inputFile="D:/kaoshi/gongshi/111222.doc";
        public static final String htmlFile="D:/kaoshi/gongshi/abc.html";


        public static void main(String argv[])
        {        
            try {
                getWordAndStyle(inputFile);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


        /**
         * word文档图片存储路径
         * @return
         */
        public static String wordImageFilePath(){


            return  "D:/kaoshi/gongshi"+ DateFormatUtil.formatDate(new Date());
        }


        /**
         *  word文档图片Web访问路径
         * @return
         */
        public static String wordImgeWebPath(){


            return "D:/kaoshi/gongshi"+ DateFormatUtil.formatDate(new Date())+"/";
        }


        /**
         * 读取每个文字样式
         * 
         * @param fileName
         * @throws Exception
         */




        public static List<Question> getWordAndStyle(String fileName) throws Exception {
        System.out.println(fileName);
            FileInputStream in = new FileInputStream(new File(fileName));
            HWPFDocument doc = new HWPFDocument(in);
            Range rangetbl = doc.getRange();//得到文档的读取范围   
            TableIterator it = new TableIterator(rangetbl); 
            int num=100;         


            beginArray=new int[num];
            endArray=new int[num];
            htmlTextArray=new String[num];


            // 取得文档中字符的总数
            int length = doc.characterLength();
            // 创建图片容器
            PicturesTable pTable = doc.getPicturesTable();


            htmlText = doc.getSummaryInformation().getTitle();
            // 创建临时字符串,好加以判断一串字符是否存在相同格式


            if(it.hasNext())
            {
                readTable(it,rangetbl);
            }


            int cur=0;


            String tempString = "";
            for (int i = 0; i < length - 1; i++) {
                // 整篇文章的字符通过一个个字符的来判断,range为得到文档的范围
                Range range = new Range(i, i + 1, doc);


                CharacterRun cr = range.getCharacterRun(0); 
                
                if(tblExist)
                {
                    if(i==beginArray[cur])
                    {         
                        htmlText+=tempString+htmlTextArray[cur];
                        tempString="";
                        i=endArray[cur]-1;
                        cur++;
                        continue;
                    }
                }
                if (pTable.hasPicture(cr)) {
                    htmlText +=  tempString ;                
                    // 读写图片                
                    readPicture(pTable, cr);
                    tempString = "";                
                } 
                else {


                    Range range2 = new Range(i + 1, i + 2, doc);
                    // 第二个字符
                    CharacterRun cr2 = range2.getCharacterRun(0);
                    char c = cr.text().charAt(0);
                    // 判断是否为空格符
                    if (c == SPACE_ASCII)
                        tempString += "&nbsp;";
                    // 判断是否为水平制表符
                    else if (c == TABULATION_ASCII)
                        tempString += "&nbsp;&nbsp;&nbsp;&nbsp;";
                    // 比较前后2个字符是否具有相同的格式
                    boolean flag = compareCharStyle(cr, cr2);
                    if (flag&&c !=ENTER_ASCII)
                        tempString += cr.text();
                    else {
                        htmlText += tempString + cr.text();
                        tempString = "";
                    }
                    // 判断是否为回车符
                    if (c == ENTER_ASCII)
                        htmlText += "<br/>";
                    
                }
            }


            htmlText += tempString;
            //生成html文件
            writeFile(htmlText);
            System.out.println("------------WordToHtml转换成功----------------");
            //word试卷数据模型化
            
            System.out.println("------------WordToHtml模型化成功----------------");
            return analysisHtmlString(htmlText);
        }


        /**
         * 读写文档中的表格
         * 
         * @param pTable
         * @param cr
         * @throws Exception
         */
        public static void readTable(TableIterator it, Range rangetbl) throws Exception {


            htmlTextTbl="";
            //迭代文档中的表格  


            counter=-1;
            while (it.hasNext()) 
            { 
                tblExist=true;
                htmlTextTbl="";
                Table tb = (Table) it.next();    
                beginPosi=tb.getStartOffset() ;
                endPosi=tb.getEndOffset();


                //System.out.println("............"+beginPosi+"...."+endPosi);
                counter=counter+1;
                //迭代行,默认从0开始
                beginArray[counter]=beginPosi;
                endArray[counter]=endPosi;


                htmlTextTbl+="<table border>";
                for (int i = 0; i < tb.numRows(); i++) {      
                    TableRow tr = tb.getRow(i);   


                    htmlTextTbl+="<tr>";
                    //迭代列,默认从0开始   
                    for (int j = 0; j < tr.numCells(); j++) {      
                        TableCell td = tr.getCell(j);//取得单元格
                        int cellWidth=td.getWidth();


                        //取得单元格的内容   
                        for(int k=0;k<td.numParagraphs();k++){      
                            Paragraph para =td.getParagraph(k);      
                            String s = para.text().toString().trim();   
                            if(s=="")
                            {
                                s=" ";
                            }
                            htmlTextTbl += "<td width="+cellWidth+ ">"+s+"</td>";
                        }       
                    }      
                }   
                htmlTextTbl+="</table>" ;    
                htmlTextArray[counter]=htmlTextTbl;


            } //end while 
        }    


        /**
         * 读写文档中的图片
         * 
         * @param pTable
         * @param cr
         * @throws Exception
         */
        public static void readPicture(PicturesTable pTable, CharacterRun cr) throws Exception {
            // 提取图片
            Picture pic = pTable.extractPicture(cr, false);
            // 返回POI建议的图片文件名
            String afileName = pic.suggestFullFileName();
            String suffix = afileName.substring(afileName.lastIndexOf(".")+1);
            String prefix = afileName.substring(0, afileName.lastIndexOf("."));
            File file = new File(wordImageFilePath());
            System.out.println(file.mkdirs());
            OutputStream out = new FileOutputStream(new File( wordImageFilePath()+ File.separator + afileName));
            pic.writeImageContent(out);
            if(suffix.equals("wmf")){
            convert(wordImgeWebPath()+afileName, wordImgeWebPath()+prefix+".svg");
            SVGUtils svgUtils = new SVGUtils();
            svgUtils.svg2PNG(new File(wordImgeWebPath()+prefix+".svg"), new File(wordImgeWebPath()+prefix+".png"));
            afileName = prefix+".png";
            htmlText += "<img src='question/getPic?path="+wordImgeWebPath()+ afileName
                    + "' mce_src='question/getPic?path="+wordImgeWebPath()+ afileName + "' style='height:30px;width:50px'/>";
            }else{
            htmlText += "<img src='question/getPic?path="+wordImgeWebPath()+ afileName
            + "' mce_src='question/getPic?path="+wordImgeWebPath()+ afileName + "' />";
            }
            
        }
      


        public static void convert(String file,String dest){ 
    try{
    InputStream in = new FileInputStream(new File(file));
            WmfParser parser = new WmfParser();
            final SvgGdi gdi = new SvgGdi(false);
            parser.parse(in, gdi);
            Document doc = gdi.getDocument();
            OutputStream out = new FileOutputStream(dest);
            if (dest.endsWith(".svgz")) {
                out = new GZIPOutputStream(out);
            }
            output(doc, out);
    }
    catch(Exception e){
    System.out.println("edn?????"+e.getMessage());
    }
       }
        public static void output(Document doc, OutputStream out) throws Exception {
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer();
            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,"-//W3C//DTD SVG 1.0//EN");
            transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
            transformer.transform(new DOMSource(doc), new StreamResult(out));
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            transformer.transform(new DOMSource(doc), new StreamResult(bos));
            out.flush();
            out.close();
    }
        public static boolean compareCharStyle(CharacterRun cr1, CharacterRun cr2) 
        {
            boolean flag = false;
            if (cr1.isBold() == cr2.isBold() && cr1.isItalic() == cr2.isItalic() && cr1.getFontName().equals(cr2.getFontName()) 
                    && cr1.getFontSize() == cr2.getFontSize()&& cr1.getColor() == cr2.getColor()) 
            {
                flag = true;
            }
            return flag;
        }


        /*** 字体颜色模块start ********/
        public static int red(int c) {  
            return c & 0XFF;  
        }  


        public static int green(int c) {  
            return (c >> 8) & 0XFF;  
        }  


        public static int blue(int c) {  
            return (c >> 16) & 0XFF;  
        }  


        public static int rgb(int c) {  
            return (red(c) << 16) | (green(c) << 8) | blue(c);  
        }  


        public static String rgbToSix(String rgb) {  
            int length = 6 - rgb.length();  
            String str = "";  
            while (length > 0) {  
                str += "0";  
                length--;  
            }  
            return str + rgb;  
        }  




        public static String getHexColor(int color) {  
            color = color == -1 ? 0 : color;  
            int rgb = rgb(color);  
            return "#" + rgbToSix(Integer.toHexString(rgb));  
        }  
        /** 字体颜色模块end ******/


        /**
         * 写文件
         * 
         * @param s
         */
        public static void writeFile(String s) {
            FileOutputStream fos = null;
            BufferedWriter bw = null;
            PrintWriter writer = null;
            try {
                File file = new File(htmlFile);
                fos = new FileOutputStream(file);
                bw = new BufferedWriter(new OutputStreamWriter(fos));
                bw.write(s);
                bw.close();
                fos.close();
                //编码转换
                writer = new PrintWriter(file, "GB2312");
                writer.write(s);
                writer.flush();
                writer.close();
            } catch (FileNotFoundException fnfe) {
                fnfe.printStackTrace();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }


        }


        /**
         * 分析html
         * @param s
         */
        public static List<Question> analysisHtmlString(String s){
        String[] split2 = s.split("&nbsp; EMBED&nbsp; Equation.DSMT4&nbsp; &nbsp; ");
        String a = "";
        for (String string : split2) {
        a+=string;
    }
        /*for (int i = 0; i < a.length(); i++) {
        char ch = a.charAt(i);
       //如果是无效字符,则替换成空字符
        if ((ch >= 0x00 && ch <= 0x08) || (ch >= 0x0b && ch <= 0x0c) || (ch >= 0x0e && ch <= 0x1f)){
        a = a.replace(ch, ' ');
        }
        }*/
            String q[] = a.split("<br/>[0-9]+、");
            List<Question> list = new ArrayList<>();
            for (int i = 1; i < q.length; i++) {
           
            Question question = new Question();
        String[] split = q[i].split("<br/>");
        String ti = split[0].substring(1, 4);
        String timu = split[0].substring(5, split[0].length());
        System.out.println(timu);
        if(ti.equals("单选题") || ti.equals("选择题")){
        question.setType(1);
        }else if(ti.equals("多选题")){
        question.setType(2);
        }else if(ti.equals("填空题")){
        question.setType(3);
        }else if(ti.equals("判断题")){
        question.setType(4);
        }else if(ti.equals("解答题") || ti.equals("问答题") || ti.equals("简答题")){
        question.setType(5);
        }
        question.setTitle("<p>"+timu+"</p>");
       
        if(ti.equals("单选题") || ti.equals("选择题")){
        question.setOptionA("<p>"+split[1].substring(2)+"</p>");
        question.setOptionB("<p>"+split[2].substring(2)+"</p>");
        question.setOptionC("<p>"+split[3].substring(2)+"</p>");
        question.setOptionD("<p>"+split[4].substring(2)+"</p>");
        question.setAnswer(split[5].substring(split[5].indexOf(":")+1));
        question.setAnalysis("<p>"+split[6].substring(split[6].indexOf(":")+1)+"</p>");
        }else{
        question.setAnswer("<p>"+split[1].substring(split[1].indexOf(":")+1)+"</p>");
        question.setAnalysis("<p>"+split[2].substring(split[2].indexOf(":")+1)+"</p>");
        }
        list.add(question);
    }
            return list;
           


           /* LinkedList<String> list = new LinkedList<String>();


            //清除空字符
            for (int i = 0; i < q.length; i++) {
                if(StringUtils.isNotBlank(q[i].toString().replaceAll("</?[^>]+>","").trim())){


                    list.add(q[i].toString().trim());
                }
            }
            String[] result = {};
            String ws[]=list.toArray(result);
            for (String string : ws) {
    System.out.println(string);
    }
            int singleScore = 0;
            int multipleScore = 0;
            int fillingScore = 0;
            int judgeScore = 0;
            int askScore = 0;
            int singleNum = 0;
            int multipleNum = 0;
            int fillingNum = 0;
            int judgeNum = 0;
            int askNum = 0;*/
            //***********试卷基础数据赋值*********************//*
            /*for (int i = 0; i < ws.length; i++) {
                String delHtml=ws[i].toString().replaceAll("</?[^>]+>","").trim();//去除html
                if(delHtml.contains("、单选题")){
                    String numScore=numScore(delHtml);
                    singleNum= Integer.parseInt(numScore.split(",")[0]) ;
                    singleScore=Integer.parseInt(numScore.split(",")[1]) ;
                }else if(delHtml.contains("、多择题")){
                    String numScore=numScore(delHtml);
                    multipleNum= Integer.parseInt(numScore.split(",")[0]) ;
                    multipleScore=Integer.parseInt(numScore.split(",")[1]) ;
                }else if(delHtml.contains("、填空题")){
                    String numScore=numScore(delHtml);
                    fillingNum= Integer.parseInt(numScore.split(",")[0]) ;
                    fillingScore=Integer.parseInt(numScore.split(",")[1]) ;
                }else if(delHtml.contains("、判断题")){
                    String numScore=numScore(delHtml);
                    judgeNum= Integer.parseInt(numScore.split(",")[0]) ;
                    judgeScore=Integer.parseInt(numScore.split(",")[1]) ;
                }else if(delHtml.contains("、问答题")){
                    String numScore=numScore(delHtml);
                    askNum= Integer.parseInt(numScore.split(",")[0]) ;
                    askScore=Integer.parseInt(numScore.split(",")[1]) ;
                }


            }
            *//**************word试卷数据模型化****************//*
            List<Map<String, Object>> bigTiMaps = new ArrayList<Map<String,Object>>();
            List<Map<String, Object>> smalMaps = new ArrayList<Map<String,Object>>();
            List<Map<String, Object>> sleMaps = new ArrayList<Map<String,Object>>();
            String htmlText="";
            int smalScore=0;
            for (int j = ws.length-1; j>=0; j--) {
                String html= ws[j].toString().trim();//html格式
                String delHtml=ws[j].toString().replaceAll("</?[^>]+>","").trim();//去除html
                if(!isSelecteTitele(delHtml)&&!isTitele(delHtml)&&!isBigTilete(delHtml)){//无
                    if(isTitele(delHtml)){
                        smalScore=itemNum(delHtml);
                    }
                    htmlText=html+htmlText;
                }else if(isSelecteTitele(delHtml)){//选择题选择项
                    Map<String, Object> sleMap = new HashMap<String, Object>();//选择题选择项
                    sleMap.put("选项", delHtml.substring(0, 1));
                    sleMap.put("选择项", html+htmlText);
                    sleMaps.add(sleMap);
                }else if(isTitele(delHtml)){//小标题
                    Map<String, Object> smalMap = new HashMap<String, Object>();//小标题
                    smalMap.put("smalTilete", html+htmlText);
                    smalMap.put("smalScore", smalScore>0?smalScore+"":itemNum(delHtml)+"");
                    smalMap.put("sleMaps", sleMaps);
                    smalMaps.add(smalMap);
                }else if(isBigTilete(delHtml)){//大标题
                    Map<String, Object> bigTiMap = new HashMap<String, Object>();//大标题
                    bigTiMap.put("bigTilete", delHtml.substring(2, 5));
                    bigTiMap.put("smalMaps", smalMaps);
                    bigTiMaps.add(bigTiMap);
                }    


            }
            for (Map<String, Object> map : sleMaps) {
    System.out.println(map.toString());
    }*/
        }


        //获取大题-题目数量以及题目总计分数
        public static String numScore(String delHtml){


            String regEx="[^0-9+,|,+^0-9]";   
            Pattern p = Pattern.compile(regEx);   
            Matcher m = p.matcher(delHtml);
            String s=m.replaceAll("").trim();
            if(StringUtils.isNotBlank(s)){
                if(s.contains(",")){
                    return s;
                }else if(s.contains(",")){
                    return s.replace(",", ",");
                }else{
                    return "0,0";
                }
            }else{
                return "0,0";
            }


        }
        //获取每小题分数
        public static int itemNum(String delHtml){
            Pattern pattern = Pattern.compile("((.*?))"); //中文括号 
            Matcher matcher = pattern.matcher(delHtml);
            if (matcher.find()&&isNumeric(matcher.group(1))){
                return Integer.parseInt(matcher.group(1));
            }else {
                return 0;
            }
        }
        //判断Str是否是 数字
        public static boolean isNumeric(String str){ 
            Pattern pattern = Pattern.compile("[0-9]*"); 
            return pattern.matcher(str).matches();    
        } 
        //判断Str是否存在小标题号
        public static boolean isTitele(String str){
            Pattern pattern = Pattern.compile("^([\\d]+[-\\、].*)"); 
            return pattern.matcher(str).matches();
        }
        //判断Str是否是选择题选择项
        public static boolean isSelecteTitele(String str){
            Pattern pattern = Pattern.compile("^([a-zA-Z]+[-\\:].*)"); 
            return pattern.matcher(str).matches();
        }
        //判断Str是否是大标题
        public static boolean isBigTilete(String str){
            boolean iso= false ;
            if(str.contains("一、")){
                iso=true;
            }else if(str.contains("二、")){
                iso=true;
            }else if(str.contains("三、")){
                iso=true;
            }else if(str.contains("四、")){
                iso=true;
            }else if(str.contains("五、")){
                iso=true;
            }else if(str.contains("六、")){
                iso=true;
            }else if(str.contains("七、")){
                iso=true;
            }else if(str.contains("八、")){
                iso=true;
            }
            return iso;
        }
    }
    展开全文
  • 在其中一个项目上,遇到一个需求是要从office文档(Word或Excel)中导入题目内容至数据库,题目内容中就有可能包括数学公式,而在文档中编辑希望使用office的公式插件来写公式元素。其实公司之前的产品已经使用.net...
  • java使用poi读写word中的公式(三)

    万次阅读 热门讨论 2019-08-09 16:03:59
    java使用poi读取word(一) java使用poi读写word中的图片(二) 准备工作 需要安装一个第三方公式插件建 AxMath官网 MathType中文官网(国内某公司代理) XML分析 先来分析一下xml 正常文本: <w:r> 标签...
  • Demo-docx4j-word.zip

    2017-12-01 14:35:20
    docx4j解析word导入试题入库,支持图片解析,mathType公式解析,word自带数学公式解析
  • **需求是这样**:老师端要上传一个带数学公式word试卷,然后在后台开始解析解析后的相关信息要能在前端页面显示出来 **已经找到的相关信息**:前端渲染可以用mathJax,但是这种有公式的怎么解析;在解析过程中...
  • 在网页中显示数学公式本网站是一个理科网站,往往会涉及数学公式的输入和显示,而这在Web上一直是一个难题。所以参考了好几篇网上的文章,现将自己的学习成果整理一下。主要参考网址:章杨的blog的Web数学公式的输入...
  • 一、考试系统需要用到导入试题功能,要求导入公式和图片。 将word 文档另存为xml 先看看图片在里面的存放效果 <w:r> <w:rPr> <w:rFonts w:hint="eastAsia" w:ascii="黑体" w:hAnsi="黑体" w:...
  • Java解析word文档

    千次阅读 2017-02-14 15:35:00
    在互联网教育行业,做内容相关的项目经常碰到的一个问题就是如何解析word文档。 因为系统如果无法智能的解析word,那么就只能通过其他方式手动录入word内容,效率低下,而且人工成本和录入出错率都较高。 疑难点 ...
  • docx4j(java解析docx)

    热门讨论 2011-05-09 16:21:25
    开源,用于java解析MS07的docx文件,或者安装了兼容包的doc文件
  • 一个word有不同的题 需要上传word拆分后存入数据库 然后在需要的时候自有组合题型并排版导出 求解!
  • wmf格式转换成svg把wmf格式转成svg格式,这样就能在浏览器中显示了需要第三方jar包:wmf2svg-0.9.6.jar//wmf格式的图片转换成svg格式 private void convert(String file,String dest) throws Exception{ ...
  • latex_word主要目的:给大家分享一个我的原创作品:latex转为word公式(omml)工具 [java]此工具主要用于将含有latex公式的文本下载成word时,将latex转换为word格式的公式如果这不是你想要的你走吧,不要给我打赏创作...
  • 我也不知道怎么实现,不知道是前端的问题还是说后端,也就是说不知道是java直接生成word 还是说前端使用js插件下载word,目前下载下来的word文档没办法编辑数学公式,因为数学公式是图片, 大体功能: word ...
  • 需求说明:数据库中存放的信息为富文本数据,并且包含了latex公式的代码,现在需要将富文本和latex公式数据输出到word文档中。 生成逻辑:将数据获取后进行遍历,获取每个节点,然后将节点增加到段落中,特别需要...
  • 在网页中显示数学公式本网站是一个理科网站,往往会涉及数学公式的输入和显示,而这在Web上一直是一个难题。所以参考了好几篇网上的文章,现将自己的学习成果整理一下。主要参考网址:章杨的blog的Web数学公式的输入...
  • javascript解析by ... 使用JavaScript解析数学表达式 (Parsing math expressions with JavaScript) A while ago, I wrote about tokenizing a math expression, with Javascript as the language of choice. The...
  • poi读取word的内容

    2020-12-19 16:53:06
    pache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。1.读取word 2003及word 2007需要的jar包读取 2003 版本(.doc)的word文件相对来说比较简单,只需要 poi...
  • java解析WMF文件

    2021-03-06 06:54:25
    2012-03-11最近实习单位布置了一个任务,就是要用java解析微软图元文件wmf图像文件的参数信息,懵懵懂懂做了一个礼拜,任务基本上完成了,在此过程中有很多误区,故在此跟大家分享一下自己的感受,希望能给有同样...
  • 我用的是office word 2016版创建文本对象XWPFDocument docxDocument = new XWPFDocument();创建段落对象XWPFParagraph paragraphX = docxDocument.createParagraph();XWPFParagraph 段落属性//paragraphX.addRun...
  • java解析docx获取文字图片并识别图片准确位置需求简述功能模块版本1生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的...
  • 3. 依赖于wiris云端服务器是加载公式插件的根本原因,css,js,post请求都依赖于wiris云端,如果网络很慢就会解析很慢 解决方案: 本地部署wiris插件服务器,js,css,post请求等,使其不依赖wiris云端 步骤: 1. 复制...
  • 该类主要是用程序来读取word文本,并拿到你想要的内容, 我这里主要是解析一道完整的数学试题, 包括(题目,选项,答案,考点,分析,解答,点评)等内容 package com.ilike.poi;import java.io.File; import java...
  • 本文使用的后台是Java。前端为Jsp(前端都一样,后台如果语言不通得自己做 Base64编码解码) 因为公司业务需要支持IE8 ,网上其实有很多富文本框,效果都很好。 例如www.wangEditor.com 但试了一圈都不支持IE8 。 ...
  • 数学公式是如何实现的?

    千次阅读 2016-08-08 10:29:42
    数学公式实现

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,831
精华内容 732
关键字:

java解析word数学公式