LTP在vs下的配置方法

最近在做自然语言相关的项目,查了下c++下比较好用的工具包,发现哈工大的语言技术平台(LTP)被推荐的很多,几年前也开源了,不但可以云上用,还可以本地用。果断下载试一下,版本是 3.3.2,但是在配置过程中还是遇到了些问题。具体的配置过程详见LTP的在线文档。文档中对于如何编译(Windows、Linux和Mac都有提到,本博文只讨论Windows)、如何配置、如何进行测试说的比较清楚,这里是自己碰到的一些问题,做一下记录,也与大家分享。

根据自己的vs版本编译出一大堆的lib和dll,博主用的是vs2013。记得还要下载模板文件,如何下载详见LTP的在线文档。下面用在线文档中的一个分词示例来说下博主遇到的问题。。。

</pre><pre name="code" class="cpp">#include <iostream>
#include <string>
#include "segment_dll.h"

int main(int argc, char * argv[]) {
    if (argc < 2) {
        std::cerr << "cws [model path]" << std::endl;
        return 1;
    }

    void * engine = segmentor_create_segmentor(argv[1]);//分词接口,初始化分词器
    if (!engine) {
        return -1;
    }
    std::vector<std::string> words;
    int len = segmentor_segment(engine,
            "爱上一匹野马,可我的家里没有草原。", words);//分词接口,对句子分词。
    for (int i = 0; i < len; ++ i) {
        std::cout << words[i] << "|";
    }
    std::cout << std::endl;
    segmentor_release_segmentor(engine);//分词接口,释放分词器
    return 0;
}

具体函数的接口和调用方法详见在线文档,说的很详细,这里不赘述。其中argv[1]上面的代码如果直接放到vs中是分词的模板文件路径,文件名为cws.model。将代码放入vs控制台工程中,配置好lib、dll、头文件后,cmd运行(注意lib和dll是debug还是release,编译时要用相应的模式编译,在线文档中说的是release版,姑且就用它吧),输入模板文件地址。等待结果,不如我们所料,并没有输出分词结果,原因是容器words长度为0,即里面没有存放数据,也就是segmentor_segment函数没有正常执行,或者说这个函数没有执行出我们期望的结果。这时,一定要从自身找问题,如果质疑LTP有问题,那么一周也出不来成果!!!好了,不卖关子,发生这种情况的原因就是字符的编码问题,LTP中使用的都是utf-8,其内部处理的字符串格式都是utf-8,包括我们的输入。在上面的代码中,我们的输入字符串"爱上一匹野马,可我的家里没有草原。"编码格式并不是utf-8,所以我们需要将普通string对象转化成utf-8的编码形式的string。上代码:

//普通sting类型 转UTF-8编码格式字符串
std::string string_To_UTF8(const std::string & str)
{
	int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);

	wchar_t * pwBuf = new wchar_t[nwLen + 1];//一定要加1,不然会出现尾巴
	ZeroMemory(pwBuf, nwLen * 2 + 2);

	::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);

	int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);

	char * pBuf = new char[nLen + 1];
	ZeroMemory(pBuf, nLen + 1);

	::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);

	std::string retStr(pBuf);

	delete[]pwBuf;
	delete[]pBuf;

	pwBuf = NULL;
	pBuf = NULL;

	return retStr;
}
//UTF-8编码格式字符串 ,转普通sting类型
std::string UTF8_To_string(const std::string & str)
{
	int nwLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);

	wchar_t * pwBuf = new wchar_t[nwLen + 1];//一定要加1,不然会出现尾巴
	memset(pwBuf, 0, nwLen * 2 + 2);

	MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), pwBuf, nwLen);

	int nLen = WideCharToMultiByte(CP_ACP, 0, pwBuf, -1, NULL, NULL, NULL, NULL);

	char * pBuf = new char[nLen + 1];
	memset(pBuf, 0, nLen + 1);

	WideCharToMultiByte(CP_ACP, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);

	std::string retStr = pBuf;

	delete[]pBuf;
	delete[]pwBuf;

	pBuf = NULL;
	pwBuf = NULL;

	return retStr;
}
注意添加相应的头文件:windows.h和io.h。有了上面两个可逆的函数,就可以进行我们的操作了。先创建一个utf-8编码的文本文件input.txt,其中只有一行数据:“中国国际广播电台创办于1941年12月3日。示例程序通过命令行参数指定模型文件路径。”简单粗暴,上代码:
int _tmain(int argc, _TCHAR* argv[])
{
	/************************************************************************/
	/*                            分词操作                                  */
	/************************************************************************/
	std::cout << "*******************分词操作*******************" << std::endl;

	void * engine = 0;
	engine = segmentor_create_segmentor("ltp_data\\cws.model");//初始化一个分词器,并读取分词模板
	if (!engine) 
	{
		std::cout << "cws engine error" << std::endl;
		return -1;
	}

	std::ifstream in("input.txt");
	std::string line;
	std::ofstream out;
	out.open("output.txt", std::ofstream::out);

	getline(in, line);
	std::cout << line << std::endl;

	std::vector<std::string> words;
	words.clear();

	int len = segmentor_segment(engine, string_To_UTF8(line), words);//进行分词操作,注意输入的字符串应该为UTF-8编码格式

	for (int i = 0; i < len; ++i) //输出结果
	{
		std::cout << UTF8_To_string(words[i]);
		if (i + 1 == len) std::cout << std::endl;
		else std::cout << "|";
		out << UTF8_To_string(words[i]) << "  ";//保证输出的是ANSI编码
	}

	std::string str1 = "返回结果中词的个数。";
	std::cout << str1 << std::endl;
	words.clear();
	len = segmentor_segment(engine, string_To_UTF8(str1), words);

	for (int i = 0; i < len; ++i)
	{
		std::cout << UTF8_To_string(words[i]);
		if (i + 1 == len) std::cout << std::endl;
		else std::cout << "|";
		out << UTF8_To_string(words[i]) << "  ";
	}

	segmentor_release_segmentor(engine);
	in.close();
	out.close();
	/************************************************************************/
	/*                          词性标注操作                                */
	/************************************************************************/
	std::cout << "*******************词性标注操作*******************" << std::endl;
	engine = postagger_create_postagger("ltp_data\\pos.model");
	if (!engine)
	{
		std::cout << "pos engine error" << std::endl;
		return -1;
	}
	words.clear();
	in.open("output.txt");
	std::string word;
	std::cout << "待分词文本:" <<std::endl;
	while (in >> word)
	{
		words.push_back(string_To_UTF8(word));
		std::cout << word << " ";
	}
	std::cout << std::endl;
	std::vector<std::string> postags;

	postagger_postag(engine, words, postags);

	for (int i = 0; i < postags.size(); i++)
	{
		std::cout << UTF8_To_string(words[i]) << "/" << UTF8_To_string(postags[i]);
		if (i == postags.size() - 1) std::cout << std::endl;
		else std::cout << " ";
	}
	postagger_release_postagger(engine);
	in.close();
	/************************************************************************/
	/*                          命名实体识别                                */
	/************************************************************************/
	std::cout << "*******************命名实体识别*******************" << std::endl;

	engine = ner_create_recognizer("ltp_data\\ner.model");
	if (!engine)
	{
		std::cout << "ner engine error" << std::endl;
		return -1;
	}
	std::vector<std::string> nertags;
	ner_recognize(engine, words, postags, nertags);

	for (int i = 0; i < nertags.size(); ++i)
	{
		std::cout << UTF8_To_string(words[i]) << "\t" << UTF8_To_string(postags[i]) 
			<< "\t" << UTF8_To_string(nertags[i]) << std::endl;
	}
	ner_release_recognizer(engine);
	/************************************************************************/
	/*                           依存句法分析                               */
	/************************************************************************/
	std::cout << "*******************依存句法分析*******************" << std::endl;

	engine = parser_create_parser("ltp_data\\parser.model");
	std::vector<int> heads;
	std::vector<std::string> deprels;

	words.clear();
	postags.clear();
	words.push_back(string_To_UTF8("一把手"));      postags.push_back("n");
	words.push_back(string_To_UTF8("亲自"));        postags.push_back("d");
	words.push_back(string_To_UTF8("过问"));        postags.push_back("v");
	words.push_back(string_To_UTF8("。"));          postags.push_back("wp");

	parser_parse(engine, words, postags, heads, deprels);

	for (int i = 0; i < heads.size(); ++i) 
	{
		std::cout << UTF8_To_string(words[i]) << "\t" << postags[i] << "\t"
			<< heads[i] << "\t" << UTF8_To_string(deprels[i]) << std::endl;
	}

	system("pause");
	return 0;
}
输出结果:











评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值