数据处理——片假名→平假名转换算法
前几天完成了一个需求,需要编写算法实现将数据集中的所有包含片假名的数据全部转换成平假名。经过调查发现,在日语中的片假名包含全角片假名、全角片假名(小号)半角片假名、片假名读音扩展这些种类的片假名。需求要求在大量数据转换过程中不可以将其他数据丢失,例如其中包含的其他字符不需要转换,但是也不可以丢失。因此我考虑到算法应该有识别数字、英文字母、空格、平假名、片假名、以及日文中的繁体字等功能。这就要明确这些字符在数据集中所占的字节长度,在此之后考虑应该建立对照表的方法完成需求。因为在数据集中的字符串是以多字节方式存储,而在编译环境中是以单字节存储,所以如果将对照表直接初始化在编译环境中,会产生字节长度不同的冲突,无法实现对应转换需求。
基于此,我尝试过将数据集中的字符串转换成单字节,此处用到了READ_ConvStringToStringEx函数,有关这方面的知识大家可以查询MultiByteToWideChar函数与WideCharToMultiByte函数的实现原理,我就不赘述了。但是在这里又遇到了困难,就是当将其转换后便无法判断字符串中字符所占内存长度,因为该方法只对多字节字符串有效。至此,只能再次更改解决方案。
最后我想到了使用外部文件导入方式,当将对照表以外部文件的形式导入时,我就可以自己定义编码方式,而在编译环境中由于没有调查清楚日文的编码方式,因此就没有实现将编译环境中的单字节字符串转化成多字节字符串的功能,基于此我的对照表建立与业务调查基本结束。接下来进行算法编写,其中数据集中与对照表中的编码方式均为UTF-8的编码方式,我们都知道,UTF-8的编码方式下字节表示是这样的:
1字节 0xxxxxxx
2字节 110xxxxx 10xxxxxx
3字节 1110xxxx 10xxxxxx 10xxxxxx
4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
其中所有片假名所占字节数均为3,因此我编写了识别算法,让获取到的数据进入循环后可以根据长度判定是需要转换还是直接截取。以下是根据字符串下标判断该元素所占内存长度方法。

if (0x00 == (strInput.at(i) & 0x80))//1字节else if ((strInput.at(i) & 0x80 && strInput.at(i) & 0x40 && strInput.at(i) & 0x20) == 0x00)//2字节else if ((strInput.at(i) & 0x80) &&(strInput.at(i) & 0x40) &&(strInput.at(i) & 0x20) &&(strInput.at(i) & 0x10) == 0x00)//3字节else if ((strInput.at(i) & 0x80) &&(strInput.at(i) & 0x40) &&(strInput.at(i) & 0x20) &&(strInput.at(i) & 0x10) &&(strInput.at(i) & 0x08) == 0)//4字节

0x80 1000 0000
0x40 0100 0000
0x20 0010 0000
0x10 0001 0000
0x08 0000 1000
如果是长度为3字节,就会进入我编写的几个循环中,因为考虑到算法的性能,我将命中率高的循环语句放置的较为靠前,并且如果在命中后就不会继续再进入其他循环,以提高性能。因为数据集中存在着同为三字节却并非是片假名的字符,因此要多加一个判定以便确保数据不会丢失。并且大家在编程时要注意每次在进入下次循环前要记得将i值向后偏移相应的长度,并且要判断i值与获取的字符串的长度关系,当两者相等时需要结束算法的最外层循环,否则会有中断。至此,算法完成,在测试时又遇到了很多问题,设置了很多断点调试,最后终于也都解决了,需求成功实现。源代码就不放了。。