欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

庖丁分词的源码分析 (5) 最多分词和最长分词

程序员文章站 2022-07-13 16:51:27
...
在字典相同的情况下,CJKKnife得到的分词结果都是一样的,都会交给collector去处理。得到的结果就是个LinkedList,不断的next得到全部的结果。collector有MaxWordLengthTokenCollector和MostWordsTokenCollector。

MaxWordLengthTokenCollector是最长分词,意思就是说一个长的分词结果包含一个小的,那么这个小的就会被过滤掉。如分词结果是二手 汽车 二手汽车,那么最后的结果只剩下二手汽车。二手和汽车这两个都会被过滤掉。而MostWordsTokenCollector这都会保留,而且还会排好序列。而最长分词已经过滤掉了包含的,已经就是排好序的了。从这里看貌似这两个分词的区别就是最长在最多的分词基础上过滤了一下而已,当然这个前提是字典一样,其实最长和最多分词他们的字典生成也是不一样的。当然最后的结果来看确实基本上是:最长分词是在最多分词的基础上过滤了一些。
MaxWordLengthTokenCollector:

public void collect(String word, int offset, int end) {
		Token c = candidate != null ? candidate : last;
		if (c == null) {
			candidate = new Token(word, offset, end);
		} else if (offset == c.startOffset()) {
			if (end > c.endOffset()) {
				candidate = new Token(word, offset, end);
			}
		} else if (offset > c.startOffset()) {
			if (candidate != null) {
				select(candidate);
			}
			if (end > c.endOffset()) {
				candidate = new Token(word, offset, end);
			} else {
				candidate = null;
			}
		} else if (end >= c.endOffset()) {
			if (last != null && last.startOffset() >= offset
					&& last.endOffset() <= end) {
				for (Iterator/* <Token> */ iter = tokens.iterator(); iter.hasNext();) {
					last = (Token) iter.next();
					if (last.startOffset() >= offset && last.endOffset() <= end) {
						iter.remove();
					}
				}
			}
			last = null;
			candidate = new Token(word, offset, end);
		}
	}


这个代码那是相当晦涩啊。总的意思是分词的开头位置和结束位置要尽量大于之前分词,这样才尽量不会被过滤掉。

MostWordsTokenCollector:
public void collect(String word, int begin, int end) {
		LinkedToken tokenToAdd = new LinkedToken(word, begin, end);
		if (firstToken == null) {
			firstToken = tokenToAdd;
			lastToken = tokenToAdd;
			return;
		}
		if (tokenToAdd.compareTo(lastToken) > 0) {
			tokenToAdd.pre = lastToken;
			lastToken.next = tokenToAdd;
			lastToken = tokenToAdd;
			//
		} else {
			LinkedToken curTokenToTry = lastToken.pre;
			while (curTokenToTry != null
					&& tokenToAdd.compareTo(curTokenToTry) < 0) {
				curTokenToTry = curTokenToTry.pre;
			}
			if (curTokenToTry == null) {
				firstToken.pre = tokenToAdd;
				tokenToAdd.next = firstToken;
				firstToken = tokenToAdd;
			} else {
				tokenToAdd.next = curTokenToTry.next;
				curTokenToTry.next.pre = tokenToAdd;
				tokenToAdd.pre = curTokenToTry;
				curTokenToTry.next = tokenToAdd;
				
			}
		}
	}


这里是不会过滤了,但是这个排序的过程嘛,也是看的我很蛋疼,呵呵。