这是久久没有写c++程序之后,写的第一个相对比较久的程序。目的就是将nist03,04,05这三个单独的测试集进行合并,以进行bleu值的测算。三个测试集中分别包含源文,参考译文,还有4个机器译文。而最后的结果就是要分别将三个测试集的源文,参考译文,以及机器译文进行合并。方法的思想其实很简单,其中源文和参考译文的合并只要将三个单独的文档合并成一个文档,并稍微改一下格式就可以完成了。而难点就在于机器译文的合并。因为每篇源文中对应了四个机器译文。 单独用文字不容易说明这个问题,我们将其形象化。比如nist03的源文是A,04的源文是B,05的源文是C。而A对应的对应的机器译文是abcd,B对应的机器译文是efgh,C对应的机器译文是ijkl。 这里解释一下什么是A对应abcd,即比如A是一整篇文档,而a,b,c,d分别是机器给出的这篇文档的4个翻译,所以机器译文的文档就是将a,b,c,d这4个译文顺序排列,并用指定的标识符来与源文进行对应。 而如果我们将源文进行合并了之后,那么源文就变成了ABC,所以机器译文也要相应做出改变,而不能单纯地将机器译文的三个文档简单合并。ABC对应的第一个机器译文是aei,第二个机器译文是bfj,第三个机器译文是cgk,第四个机器译文是dhl,所以我们将机器译文合并后的排列顺序就应该调整为aeibfjcgkdhl。由于对于c++我是初学者,所以我实现的方法可能比较粗暴简单。对于每个机器译文,在最开始都有一个<DOC docid= 的标识符来标识指定的翻译,而末尾都有</DOC>来进行结束。因此我们只要根据这两个标识符就可以区分出所有的机器翻译,然后再对其进行重新组合。以其中一个代码为例: 1 string PartOne(string s)
2 {
3 size_t x=0,y=1,z=0;
4 string tmp;
5 x=s.find("<DOC docid=\"AFC20030102.0015\" sysid=\"E01\">");
6 y=s.rfind("sysid=\"E01\"");
7 z=s.find("</DOC>",y);
8 tmp.append(s,x,z-x+6);
9 return tmp;
10 }
这个代码是分割出nist03中的第一个机器译文,我们可以看出<DOC docid=\"AFC20030102.0015\" sysid=\"E01\">" 是这个译文的标识符,E01表示的是第一个译文,同理E02,E03,E04表示的就是第二,第三,第四个译文。 而由于nist03,04,05的机器译文格式不完全一样,因此为了最后计算bleu值时能够被识别,必须将所有机器译文的格式进行统一(我一开始就是没有将格式进行统一,以至于合并了之后也无法计算bleu值)。 1 string PartTwo(string s)
2 {
3 size_t x=0,y=1,z=0;
4 string tmp;
5 x=s.find("<DOC docid=\"PD20040202.001\" sysid=\"cha\">");
6 y=s.rfind("sysid=\"cha\"");
7 z=s.find("</DOC>",y);
8 tmp.append(s,x,z-x+6);
9 int pos=0;
10 while(1)
11 {
12 pos=tmp.find("sysid=\"cha\"",pos+5);
13 if (-1 == pos)
14 break;
15 else
16 tmp = tmp.substr(0,pos)+"sysid=\"E01\""+tmp.substr(pos+11);
17
18 }
19 return tmp;
20 }
以这个例子来说明,这是分割出nist04的第一个机器译文,而由于nist04的机器译文中,第一个译文是用 sysid="cha"来进行识别,因此第11行到第18行就是进行格式的统一,将cha替换成E01(我们这里默认都使用跟nist03一样的格式)。后面的机器译文也是使用类似的方法进行处理。 这样将所有译文都分割出来并统一格式之后,再将他们合并之后就完成了整个代码的编写。 这里再给出将所有代译文合并的过程: 1 out<<"<refset setid=\"mt05_chinese_eval\" srclang=\"zh\" trglang=\"en\">";
2 out<<PartOne(n3)<<endl<<PartTwo(n4)<<endl<<PartThree(n5)<<endl
3 <<PartOneS(n3)<<endl<<PartTwoS(n4)<<endl<<PartThreeS(n5)<<endl
4 <<PartOneT(n3)<<endl<<PartTwoT(n4)<<endl<<PartThreeT(n5)<<endl
5 <<PartOneF(n3)<<endl<<PartTwoF(n4)<<endl<<PartThreeF(n5)<<endl;
6 out<<"</refset>";
头尾的两个out是输出特定的首尾格式。out是将其输出到事先指定好的文档中。 最后对这个编写代码的过程进行思考总结。首先可能由于我对c++的编写不是太熟练,很多方法也不会用,因此将这个看去其实很简单的代码也写了好久,并不断修正各种小错误。其中遇到最大的困难还是不知道要如何更便捷的修改格式,因此采用了最粗暴的方式,这样可能会导致算法的复杂度更高,需要消耗的时间更久,在以后的学习过程中希望能够学会使用更简便的方法。