最近有一个需求,有一个老的数据库,里面存了2000多道高数题目,同时还有题目的答案、解题过程、用到的知识点,他们都是以trf文本的方式保存。例如:
{\rtf1\adeflang1025\ansi\ansicpg936\uc2\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi0\deflang1033\deflangfe2052\themelang1033\themelangfe2052\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
{\f13\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'cb\'ce\'cc\'e5{\*\falt SimSun};}{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;}
{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\f38\fbidi \fswiss\fcharset0\fprq0{\*\panose 00000000000000000000}MS Sans Serif{\*\falt Arial};}
{\f39\fbidi \fnil\fcharset134\fprq2{\*\panose 0201060003010101010...
然后保存成rtf后,用word打开就是一个个和数学相关的内容:
这一整个内容都是一个ole对象,嵌入到一个rtf中
处理过数学题目的朋友们都知道,数学公式的显示、保存、输入等是一个比较麻烦的问题,在这个数据库中保存的所有的内容都是一长串的rtf文本,文本保存的是数学公式和题目描述,需要将他们转成MathML,以方便在网页上显示。
在MathML提供的SDK中,有ConvertEquation这个类,这个类的作用就是格式的转换,如下是MathType所提供的输入的格式和输出的格式:
通过描述能够看出,除了在Word嵌入的对象(Embedded Object),不能将word作为文件直接传入,其他的格式都能直接输入文件,然后输出.text文本。因为数据库中的数据量太大,所以想到通过程序,将word中ole对象复制到剪贴板,然后再调用MathType提供的接口,实现。
具体操作如下:
首先初始化一些用到的对象
static word.ApplicationClass wordapp = null;
static word.Document doc = null;
static word.Selection selection = null;
static object omissing = System.Reflection.Missing.Value;
打开文档:
//打开文档
public static void OpenDocFile(string docName)
{
wordapp = new word.ApplicationClass();
wordapp.Visible = false;
object docObject = docName;
doc = wordapp.Documents.Add(ref docObject, ref omissing, ref omissing, ref omissing);
doc.Activate();
int ParagraphCount = doc.Content.Paragraphs.Count;
Console.WriteLine(ParagraphCount);
}
(建议讲wordapp.Visible设为false,表示打开文档但是不显示出来,这么做会提高些速度,不会造成卡顿)
然后分析word文件,结构非常简单,只有ole对象,对象前面有一连串的空格,所以思路就是首先将光标定义到文档最开始,然后一个字符一个字符的朝下走,当走到不是字符的时候停止,那么下一个字符就是所需要的ole对象,然后执行复制就好。
执行复制的操作在 selection.MoveRight(ref unit, ref count, ref extend);
处,需要注意最后一个传入的参数是word.WdMovementType.wdExtend
。关于这个参数可以使用Word里面非常强大的录制宏,查看宏作为向导(此处录制宏非常简单,就是移动到ole对象然后执行复制),VBA 宏如下:
Sub 宏()
'
' 宏 宏
'
'
Selection.MoveRight Unit:=wdCharacter, Count:=6
Selection.MoveRight Unit:=wdCharacter, Count:=1, Extend:=wdExtend
Selection.Copy
End Sub
可以看见执行复制操作是先设置wdExtend
,然后执行Selection.Copy()
,复制到剪贴板。
所以代码如下:
向下一个字符复制并且移动:
//向右移动count个单位并进行复制
public static void CopyAndMove(object count)
{
object dummy = System.Reflection.Missing.Value;
object value = 1;
object unit = word.WdUnits.wdCharacter;
object extend = word.WdMovementType.wdExtend;
selection.MoveRight(ref unit, ref count, ref extend);
selection.Copy();
selection.MoveRight(ref unit, ref value, ref dummy);
}
其中selection.MoveRight(ref unit, ref value, ref dummy);
是为了将光标移动向下一个单位。
当下一个字符不是空格时,停止:
public static void CopyOleObject()
{
do
{
CopyAndMove(1);
} while (Paste().Equals(" "));
}
然后进行复制就可以将OLE对象添加到剪贴板,但是在使用剪贴板时出现一个问题,无法使用Clipboard对象,查阅发现,将main方法设置为单线程模式就可以。 [STAThread]
static void Main(string[] args)
{
OpenDocFile("F:\\doc\\l.rtf");
Console.WriteLine(getCurrentPos());
CopyOleObject();
Console.WriteLine(getCurrentPos());
Console.WriteLine("数据是:"+Paste() + "结束");
Console.ReadLine();
}
至此完成操作,然后将MathType的接口嵌入就可以。
示例:
<!-- MathType@Translator@5@5@MathML2 (m namespace).tdl@MathML 2.0 (m namespace)@ -->
<m:math>
<m:semantics>
<m:mrow>
<m:mi>y</m:mi><m:mo>=</m:mo><m:mfrac>
<m:mrow>
<m:msup>
<m:mi>a</m:mi>
<m:mi>x</m:mi>
</m:msup>
<m:mo>+</m:mo><m:msup>
<m:mi>a</m:mi>
<m:mrow>
<m:mo>−</m:mo><m:mi>x</m:mi></m:mrow>
</m:msup>
</m:mrow>
<m:mn>2</m:mn>
</m:mfrac>
</m:mrow>
<m:annotation encoding='MathType-MTEF'>MathType@MTEF@5@5@+=
feaagKart1ev2aqatCvAUfeBSjuyZL2yd9gzLbvyNv2CaerbuLwBLn
.....