最新:中文分词技术 ( 积分: 73 )

  • 主题发起人 主题发起人 zqssoft
  • 开始时间 开始时间
Z

zqssoft

Unregistered / Unconfirmed
GUEST, unregistred user!
已知在一个Memo1控件中,有如下的文本:
我是一个中国人,我爱我的祖国和人民。yes.

在另一个Memo2控件中,有如下的词组序列:
中国人
一个
中国
祖国
人民







o
.

如何将Memo1中的文本,按Memo2序列中词组的排列顺序,分成如下的格式,并显示在Memo3中?


一个
中国人





祖国

人民

yes
.

请各位指点,能答多少答多少,谢谢,73分全部相送。
 
var
//长度大的词放在前面,搜索的时候从长的词优先
Words: array[0..4] of WideString = (
'中国人',
'一个',
'祖国',
'人民',
'我的'
);

//比较PWidechar是否相等
function CompPWideChar(P1, P2: PWideChar; Len: Integer): Boolean;
var
I: Integer;
begin
Result := False;
for I := 0 to Len - 1 do
begin
if P1 <> P2 then
Exit;
end;
Result := True;
end;

//分词
function GetWordLen(P: PWideChar; var S: WideString): Integer;
var
I: Integer;
PP:PWideChar;
begin
PP := P;
case PP^ of
//英文字母
WideChar('_'),WideChar('a')..WideChar('z'),WideChar('A')..WideChar('Z'):
begin
Result := 1;
Inc(PP);
While PP^ in [WideChar('_'),WideChar('a')..WideChar('z'),WideChar('A')..WideChar('Z')] do
begin
Inc(Result);
Inc(PP);
end;
end;
//标点符号
WideChar(','),WideChar('.'): //半角符号
Result := 1;
//数字
WideChar('0')..WideChar('9'):
begin
Result := 1;
Inc(PP);
While PP^ in [WideChar('0')..WideChar('9'),WideChar('.')] do
begin
Inc(Result);
Inc(PP);
end;
end;
else //除去上面的就看成是中文。
//到词汇数组里面搜索。找不到的全部算成是长度为1的字
for I := Low(Words) to High(Words) do
begin
Result := Length(Words);
if CompPWideChar(PWideChar(Words), PP, Result) then
Break;
Result := 1;
end;
end;
SetLength(S, Result);
CopyMemory(PWideChar(S), P, Result * SizeOf(WideChar))
end;

//跳过空格
procedure SkipBlank(var P: PWideChar);
begin
while True do
begin
case P^ of
WideChar(' '), WideChar(#10), WideChar(#13):
begin
Inc(P);
end;
else
Exit;
end;
end;
end;

//分词的主函数
procedure CWord(V: WideString; R: TStrings);
var
P: PWideChar;
S: WideString;
begin
R.BeginUpdate;
R.Clear;
P := PWideChar(V);
while P^ <> WideChar(0) do
begin
SkipBlank(P);
Inc(P, GetWordLen(P, S));
R.Add(S);
end;
R.EndUpdate;
end;

使用方法:
CWord('我是一个中国人,我爱我的祖国和人民。yes.', Memo1.Lines);
 
也就是说,Memo中提供了组词规则,而你的串则提供了资源和顺序
因此只要将你的源串 按照从头到尾 去匹配组词规则直至结束就可以了
 
复杂的算法要用到分类器 神经网络等人工AI。。
 
能不能把Memo2控件中的字符串资源直接利用上,而不要用

var
//长度大的词放在前面,搜索的时候从长的词优先
Words: array[0..4] of WideString = (
'中国人',
'一个',
'祖国',
'人民',
'我的'
);

上面的形式,因为,如果涉及到大量的文本,可能所需要排列的字符串资源很长.
不适合在Delphi中进行直接的声明.谢谢.
 
自己顶一下,请大侠复答,谢谢。
 
wr960204使用的是长词优先最大匹配,最基本的~

http://www.delphibbs.com/delphibbs/dispq.asp?lid=3221160

我给几个思路:
A) 基于一个树~

/ /
家(E) 人(E)
/ /
们 (E) 物(E)
==========================
B) 最大匹配法分词示例:
1》S1="计算语言学课程是三个课时"
2》 设定最大词长MaxLen = 5

S2= " "
3》(1)S2="";S1不为空,从S1左边取出候选子串W="计算语言学";
(2)查词表,“计算语言学”在词表中,将W加入到S2中,S2=“计算语言学 ”, 并将W从S1中去掉,此时S1="课程是三个课时";
(3)S1不为空,于是从S1左边取出候选子串W="课程是三个";
(4)查词表,W不在词表中,将W最右边一个字去掉,得到W="课程是三";
(5)查词表,W不在词表中,将W最右边一个字去掉,得到W="课程是";
(6)查词表,W不在词表中,将W最右边一个字去掉,得到W="课程"
(7)查词表,W在词表中,将W加入到S2中,S2=“计算语言学/ 课程/ ”,并 将W从S1中去掉,此时S1="是三个课时";
(8)S1不为空,于是从S1左边取出候选子串W="是三个课时";
(9)查词表,W不在词表中,将W最右边一个字去掉,得到W="是三个课";
(10)查词表,W不在词表中,将W最右边一个字去掉,得到W="是三个";
(11)查词表,W不在词表中,将W最右边一个字去掉,得到W="是三"
(12)查词表,W不在词表中,将W最右边一个字去掉,得到W=“是”,这时 W是单字,将W加入到S2中,S2=“计算语言学/ 课程/ 是/ ”,并将 W从S1中去掉,此时S1="三个课时";
(13)S1不为空,从S1左边取出候选子串W="三个课时";
(14)查词表,W不在词表中,将W最右边一个字去掉,得到W="三个课";
(15)查词表,W不在词表中,将W最右边一个字去掉,得到W="三个";
(16)查词表,W不在词表中,将W最右边一个字去掉,得到W=“三”,这时 W是单字,将W加入到S2中,S2=“计算语言学/ 课程/ 是/ 三/ ”,并 将W从S1中去掉,此时S1="个课时";
(17)S1不为空,从S1左边取出候选子串W="个课时";
(18)查词表,W不在词表中,将W最右边一个字去掉,得到W="个课";
(19)查词表,W不在词表中,将W最右边一个字去掉,得到W=“个”, 这时W是单字,将W加入到S2中,S2=“计算语言学/ 课程/ 是/ 三/ 个/ ",并将W从S1中去掉,此时S1="课时";
(20)S1不为空,从S1左边取出候选子串W="课时";
(21)查词表,W在词表中,将W加入到S2中,S2=“计算语言学/ 课程/ 是/ 三/ 个/ 课时/ ",并将W从S1中去掉,此时S1=""。
(22)S1为空,输出S2作为分词结果,分词过程结束。

==============================
C)最大概率法分词:

基本思想是:
(1)一个待切分的汉字串可能包含多种分词结果
(2)将其中概率最大的那个作为该字串的分词结果

有 意 见 分 歧
0 1 2 3 4 5

路径1: 0-1-3-5 (有/意见/分歧)
路径2: 0-2-3-5 (有意/见/分歧) 该走哪条路呢????
=================================
不好意思,代码不能贴呢~~
 
我看老兄把老本都拿出来了~
不过73分,我要70哦~

^_^~
 
接受答案了.
 
后退
顶部