其实这个代码我写了两个版本,第一个版本仅仅是为了实现功能,而没有去考虑算法的复杂度与计算时间,而由于统计的语料是100万的语料,因此用第一个版本用了两三个小时都得不出结果。所以我在向学长请教之后,写出了第二个改进的版本,虽然耗时还是比较长,但是总算能够得出结果,而我也希望在日后的学习过程中能够能写出更优的算法。 算法的整体思想同样也比较简单,就是遍历整篇文档,切分其中的句子,再对句子进行单独的操作。对单个句子中,先遍历得出其中所有的源语言规则,同时统计其对齐信息,存放到map中,之后再判断是否满足对齐一致性,分别将所有出现的次数以及满足对齐一致性的次数存入两个map中,最后再输出结果。接下来看看具体代码。由于源语言以及对齐信息对是连续的string,但是有用空格进行切分,因此首先写了一个小函数将每个部分单独切分出来,以便于后面的使用: 1 inline vector<string> split_word(string str,string sym)
2 {
3 str+=sym;
4 vector <string> result;
5 size_t pos;
6 int size=str.size();
7 for(int i=0; i<size; i++)
8 {
9 pos=str.find(sym,i);
10 if(pos<size)
11 {
12 string sub_string=str.substr(i,pos-i);
13 if(sub_string.length()!=0)
14 {
15 result.push_back(sub_string);
16 }
17 i=pos+sym.size()-1;
18 }
19 }
20 return result;
21 }
这里使用了inline是因为之前看到内联函数适用于那些频繁使用的小函数,有利于提高运行效率。这里str表示的是需要进行切分的整串string,而sym表示的就是切分依据的分隔符,比如空格。第三行中在str后面又加了一个sym是为了便于切分,因为切分依据都是先找到sym的位置,再切分出sym的位置与初始位置之间的字符串。 接下来是将源语言对齐到目标语言的信息与目标语言对齐到源语言的对齐信息存入两个map中,由于其中可能存在一对多的情况,因此使用了map<int,vector<int> >来存取多个对齐关系。 1 void get_alignment_relationship(string alignment, map<int,vector<int> > &stt_alignment, map<int,vector<int> > &tts_alignment)
2 {
3 vector<string>alignment_element = split_word(alignment," ");
4 assert (alignment_element.size()>=0);
5 for (int i=0; i<alignment_element.size(); i++)
6 {
7 vector<string>s_t_index= split_word(alignment_element[i],"-");
8 int s_index = atoi(s_t_index[0].c_str());
9 int t_index = atoi(s_t_index[1].c_str());
10
11 stt_alignment[s_index].push_back(t_index);
12 tts_alignment[t_index].push_back(s_index);
13 }
14 map<int,vector<int> >::iterator it1,it2;
15 it1=stt_alignment.begin();
16 stt_alignment.erase(it1);
17 it2=tts_alignment.begin();
18 tts_alignment.erase(it2);
19 }
stt_alignment 表示的是source to target,即源语言对齐到目标语言的对齐关系,而反之,tts_alignment 则表示目标语言对齐到源语言的对齐关系。 在得到对齐关系之后,通过判断对齐连线个数来判断是否符合对齐一致性: 1 inline bool is_fit_alignment(map<int,vector<int> > stt_alignment, map<int,vector<int> > tts_alignment, size_t s_begin, size_t s_end)
2 {
3 int src_size=0,tgt_size=0;
4 map<int,int> tgtcount;
5 map<int,int>::iterator iter;
6 for (int x=s_begin;x<s_end;x++)
7 {
8 src_size+=stt_alignment[x].size();
9 for (size_t a=0;a<stt_alignment[x].size();a++)
10 {
11 tgtcount[stt_alignment[x][a]]++;
12
13 }
14 }
15 for(iter=tgtcount.begin();iter!=tgtcount.end();iter++)
16 {
17 tgt_size+=tts_alignment[iter->first].size();
18 }
19 if (src_size==tgt_size && src_size!=0)
20 return true;
21 return false;
22 }
通过bool函数来判断是否满足对齐一致性。 以上就是一些主要的函数方法。写完这个代码最大的收获就是由于之前不懂得怎么在函数中返回STL容器,因此当遇到需要使用map或者vector之类的容器时,就只好在main函数中实现,而现在了解了可以在函数中使用指针来返回容器。这对于以后代码的编写提供了非常大的便利。而且通过写这个代码,也对于语料的结构以及怎么处理语料有了更深入的了解,这对于以后编写自然语言处理方面的代码有了很大的帮助。