【IT面试题007】英语字符串的分词程序

/*
给你一个没有间隔的字符串“thisisasentence”,如何将他分割成如下的句子:“this is a sentence”。
提供一个函数用来检验一个字符串是不是单词:bool dic(char* w);
完成下列的函数。要求效率尽可能快。
bool Detect(char* str)
{

}

尽量写出完整思路,最好有伪代码。
提示: 递归,回溯。这里使用最长单词优先匹配 + 深度优先搜索+回溯的方法解决此问题。
其中数据来源为一篇普通的英文文字,测试时大概有几千个英文单词,先进行预处理,
得到长字符串和单词词典。在实现时,由于使用的是stl的string,接口和题目中给出的有所处理,
但不影响解决该问题。本程序中 Go(str,startIdx) 意为对str(startIdx:)进行分词
而bool dic(char * w)其实就是程序中对词典map的find操作
*/

#include "stdafx.h"

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <map>
using namespace std;

int maxWordLen = 0;
char puncs[] = {'.',',','-',')','(','[',']','\"'};
string splitResult[1000000];
bool bSuc = false;
//已分的词的个数
int splittedWordNum = 0;
map<string,int> wordDic;

//判断是否是标点
bool isPunc(char ch)
{
	for (int i = 0;i < sizeof(puncs);i++)
	{
		if (ch == puncs[i])
		{
			return true;
		}
	}
	return false;
}

//从文件构造长字符串和词典
void ReadFromFile(const string & filePath,string& strSentence,
				  map<string,int>& wordDic)
{
	ifstream fin(filePath.c_str());
	string str;
	string word;
	int wordOccured = 0;
	while (fin >> str)
	{
		int firstIdx = 0;
		while(firstIdx < str.size() && isPunc(str[firstIdx]))
		{
			firstIdx++;
		}
		int secIdx = str.size() - 1;
		while(secIdx >=0 && isPunc(str[secIdx]))
		{
			secIdx --;
		}
		if (secIdx >= firstIdx)
		{
			word = str.substr(firstIdx,secIdx - firstIdx + 1);
			wordDic[word] = 1;
			strSentence = strSentence + word;
			if (secIdx - firstIdx + 1 > maxWordLen)
			{
				maxWordLen = secIdx - firstIdx + 1;
			}
			wordOccured++;
			//cout << word << " ";
		}
	}
	cout << wordOccured << endl;
	fin.close();
}
void PrintSplitResult()
{
	for (int i = 0;i<splittedWordNum;i++)
	{
		cout << splitResult[i] << " ";
	}
}
void Go(string & strSentence,int startIdx)
{
	//如果已经有分词成功,则结束
	if (bSuc)
	{
		return;
	}
	//分词完毕
	if (startIdx == strSentence.size())
	{
		PrintSplitResult();
		//cout << endl;
		//cout << splittedWordNum << endl;
		bSuc = true;
		return;
	}

	//否则从最长的词开始匹配
	int maxLen = strSentence.size() - startIdx;
	if (maxLen > maxWordLen)
	{
		maxLen = maxWordLen;
	}

	for (int len = maxLen;len >0;len--)
	{
		string candidateWord = strSentence.substr(startIdx,len);
		//该词存在于词典
		if (wordDic.find(candidateWord) != wordDic.end())
		{
			splittedWordNum ++;
			splitResult[splittedWordNum - 1] = candidateWord;
			//递归对下标startIdx + len开头的字符串进行分词
			Go(strSentence,startIdx + len);
			splittedWordNum --; // 这里需要回溯
		}
	}
	
}
int _tmain(int argc, _TCHAR* argv[])
{
	string strSentence;
	string filePath = "file2.txt";
	ReadFromFile(filePath,strSentence,wordDic);
	

	Go(strSentence,0);

	//cout << wordDic.size() << endl;
	//cout << splittedWordNum << endl;
	if (!bSuc)
	{
		cout << "分词失败!!" << endl;
	}

}

posted on 2011-06-05 21:49  speedmancs  阅读(1055)  评论(0编辑  收藏  举报

导航