输入法最核心的是输入法引擎,输入法引擎负责加载和管理输入法配置和输入法的词库,输入法引擎对用户输入的拼音字符串进行处理并返回对应的候选列表。通过引入输入法引擎我们就可以将我们输入法的拼音串转换成对应的中文候选了。
这里我不建议用户自己开发输入法引擎,这个难度还是很大的,涉及到了音节拆分和智能组词等等。如果是简单的使用的话,采用开源的输入法引擎库就行,这里我采用的是谷歌的开源输入法引擎,引擎项目的地址如下:
GitHub – lelelongwang/GooglePinyinIME: Google 拼音输入法
由于谷歌拼音输入法的引擎接口比较多,新手调用起来比较吃力,这里对输入法的引擎进行了简单的封装,封装之后就可以无脑使用了。封装的接口如下:
//pinyin_engline.h
#ifndef _PINYIN_ENGINE_H_
#define _PINYIN_ENGINE_H_
#include <QObject>
class pinyin_engine : public QObject
{
Q_OBJECT
public:
explicit pinyin_engine (QObject *parent = 0);
~pinyin_engine ();
public:
/**@brief 初始化输入法引擎
* @param[in] dir 词库文件的目录
* @param[in] max_spell_len 字符串最长的长度默认64
* @param[in] max_output_len 输出中文文本的最长长度
* @return 函数执行结果
* - 1 执行成功
* - 0 执行错误
*/
bool init(const QString &dir = "", int max_spell_len = 64, int max_output_len = 64);
/**@brief 关闭输入法引擎
*/
void deinit();
/**@brief 清空词库缓存
*/
void flush_cache();
/**@brief 通过拼音的拼音字符串查找对应的候选结果
* @param[in] search 拼音字符串
* @return 候选词的个数
*/
unsigned int search(const QString &spell);
/**@brief 删除候选拼音串中的音节然后重新获取候选
* @param[in] pos 删除音节的位置
* @return 候选词的个数
*/
unsigned int del_search(unsigned pos);
/**@brief 对检索进行重置
*/
void reset_search();
/**@brief 查找正在检索的音节的位置
* @return 对应的位置
*/
unsigned short cur_search_pos();
/**@brief 获取固定索引位置的候选词
* @param[in] index 候选词索引的位置
* @return 候选词字符串
*/
QString get_candidate(unsigned int index);
/**@brief 选择部分音节的候选词作为部分词
* @param[in] index 部分音节的候选词
* @return 候选词的个数
*/
unsigned int choose(unsigned int index);
/**@brief 取消上一次的候选
* @return 返回取消候选之后的候选词的个数
*/
unsigned unchoose();
private:
bool m_enable; //引擎开关
int m_spell_len; //字符串长度
int m_output_len; //输出字符串的长度
};
#endif
//pinyin_engline.cpp
#include "pinyin_engine.h"
#include <QApplication>
#include <pinyinime.h>
#include <string.h>
using namespace ime_pinyin;
//系统词库的名称
#define DICT_PATH "dict_pinyin.dat"
//用户词库的名称
#define DICT_USER_PATH "dict_pinyin_user.dat"
//最多的汉字的候选个数
#define MAX_SINGLE_ZI 60
static size_t fix_cand_len (size_t cand, int output_len)
{
size_t i;
size_t decode_len;
size_t single = 0;
size_t multi = 0;
char16 *cand_buf = new char16[output_len];
//查找字拼音串中还没有被解析出来的拼音串的长度
im_get_sps_str(&decode_len);
//如果只有一个拼音字符的话候选只保留10个
if (decode_len == 1) {
if (cand > 10) {
cand = 10;
}
delete cand_buf;
return cand;
}
for (i = 0; i < cand; i++) {
//查找满足固定长度的候选
im_get_candidate(i, cand_buf, output_len);
//候选词的个数
if (strlen((char *)cand_buf) > 2)
{
multi++;
}
//候选字的个数
else
{
single++;
if (single > MAX_SINGLE_ZI) {
break;
}
}
}
cand = multi + single;
delete cand_buf;
return cand;
}
pinyin_engine::pinyin_engine(QObject *parent) :
QObject(parent),m_enable(false)
{
}
pinyin_engine::~pinyin_engine()
{
}
bool pinyin_engine::init(const QString &dir, int max_spell_len, int max_output_len)
{
bool ret;
QString app_dir = dir;
if (app_dir.isEmpty()) {
app_dir = qApp->applicationDirPath() + "/dict";
}
//打开用户词库和系统词库
ret = im_open_decoder(QString("%1/" DICT_PATH).arg(app_dir).toLocal8Bit().data(),
QString("%1/" DICT_USER_PATH).arg(app_dir).toLocal8Bit().data());
m_enable = ret;
if (ret == false) {
return ret;
}
im_set_max_lens(max_spell_len ,max_output_len);
reset_search();
m_spell_len = max_spell_len;
m_output_len = max_output_len;
return ret;
}
void pinyin_engine::deinit()
{
im_close_decoder();
}
void pinyin_engine::flush_cache()
{
im_flush_cache();
}
unsigned int pinyin_engine::search(const QString &spell)
{
if (!m_enable)
{
return 0;
}
QByteArray bytearray;
char *pinyin;
bytearray = spell.toUtf8();
pinyin = bytearray.data();
bytearray.size();
size_t cand = im_search(pinyin, bytearray.size());
cand = fix_cand_len(cand, m_output_len);
return (unsigned)cand;
}
unsigned int pinyin_engine::del_search(unsigned pos)
{
if (!m_enable)
{
return 0;
}
size_t cand = im_delsearch(pos, false, false);
cand = fix_cand_len(cand, m_output_len);
return (unsigned)cand;
}
void pinyin_engine::reset_search()
{
if (!m_enable)
{
return;
}
im_reset_search();
}
unsigned short pinyin_engine::cur_search_pos()
{
const uint16 *start_pos;
size_t pos_len;
size_t fixed_len = im_get_fixed_len();
pos_len = im_get_spl_start_pos(start_pos);
if (fixed_len <= pos_len) {
return (start_pos[fixed_len]);
}
return 0;
}
QString pinyin_engine::get_candidate(unsigned int index)
{
char16 *cand_buf = new char16[m_output_len];
char16 *cand;
QString cand_str;
cand = im_get_candidate(index, cand_buf, m_output_len);
if (cand) {
cand_str = QString::fromUtf16(cand);
if (index == 0) {
cand_str.remove(0, im_get_fixed_len());
}
} else {
cand_str = "";
}
delete cand_buf;
return cand_str;
}
unsigned int pinyin_engine::choose(unsigned int index)
{
size_t left;
left = im_choose(index);
left = fix_cand_len(left, m_output_len);
if (left < 1)
{
return 0;
} else {
return (left - 1);
}
}
unsigned pinyin_engine::unchoose()
{
size_t cand = im_cancel_last_choice();
cand = fix_cand_len(cand, m_output_len);
return (unsigned)cand;
}
通过封装的接口我们就可以很方便的将用户输入的音节字符串转换成对应的中文候选了,这个功能是输入法的基础,很重要。