这几天刚整理完Kudy.Net项目中关键词过虑的功能。关键词过虑在网站开发中也算是比较常见的需求了,特别是在SNS社区网站。在网上找的相关文章都达不到我的要求,所以就自己根据过虑的特点专门写了个KeywordFilter,可能满足基本的过虑要求,性能也不错。它有如下特点:
一、允许你自定义匹配到关键词时返回的结果,例如匹配到“日-你”,你可以在原文中显示例如:“”、“**”、“[已过虑]”...
二、允许你按关键词或者关键词的使用频率的排序的优先顺序进行过虑。
三、允许大小写是否敏感(性能上几乎不变),可设置关键词中可跳过的字符,例如设置可跳字符为“▇☆”,关键词里有“我爱你”,那么“我▇爱☆☆你”也会被成功过虑。
备注:如果设置了可跳字符,只会过虑有关键词出现的地方,例如上面“▇我▇爱☆☆你▇”过虑后只有“▇▇”。(哈哈,发现博客园的过虑并没有这功能)
既然是简单的处理过虑,里面当然没有做分词的处理,所以有些句子可能会被误报,只要设置重要的敏感禁用词即可。
打算下个文章给大家讲一下过虑的实现的思路的,另外再发个算法的源码大家学习。 我还想说的是,有的源码不提供出来大家也不用语言攻击,我提供功能出来你要用就用,不用就直接飘过即可,公司项目的源码我怎么会直接放源码出去?
实现思路:关键字过虑实现的思路及Aho–Corasick高效字符串匹配算法应用(附算法C#实现和测试)
更多请关注: KudyStudio文章目录
功能实现的相关成员有:Keyword、KeywordOrder、KeywordFormatter、KeywordFilterResult、KeywordFilter、HighlightFormatter、Highlighter。
1.Keyword类,主要有两个属性,Text和Frequency,分别表示关键词文本与它的使用频率(这个属性是可选的),如果从文本中转换为关键词列表,那文本格式是这样的:
Keyword1
Keyword2
或
Keyword1|Frequency1
Keyword2|Frequency2
[Serializable]
public
sealed
class
Keyword
{
public
Keyword(
string
text);
public
Keyword(
string
text,
int
frequency);
public
static
implicit
operator
string
(Keyword keyword);
public
static
implicit
operator
Keyword(
string
keyword);
public
string
Text {
get
; }
public
int
Frequency {
get
;
set
; }
public
override
bool
Equals(
object
obj);
public
override
int
GetHashCode();
public
override
string
ToString();
}
|
2.KeywordOrder枚举,表示过虑时匹配的顺序,允许你按文本或使用频率排序,定义如下:
[Serializable]
public
enum
KeywordOrder
{
None = 0,
Ascending = 1,
Descending = 2,
ByFrequencyAscending = 3,
ByFrequencyDescending = 4,
}
|
3.KeywordFormatter类,这个是抽象类,它的作用就是在匹配到关键词时怎么格式化关键词并返回,里面默认实现了常量和重复字符的Formatter,如果还需要特殊的格式化需求,只要继承KeywordFormatter并实现Format(string keyword)方法即可,下面提到的HighlightFormatter就是其中一个例子。
public
abstract
class
KeywordFormatter
{
public
static
readonly
KeywordFormatter ToEmpty;
public
static
readonly
KeywordFormatter ToIterantStar;
public
static
KeywordFormatter CreateConstFormatter(
char
replacement);
public
static
KeywordFormatter CreateConstFormatter(
string
replacement);
public
static
KeywordFormatter CreateIterantCharFormatter(
char
replacement);
public
abstract
string
Format(
string
keyword);
}
|
4.KeywordFilterResult类,它表示过虑结果,包括过虑后的字符串和被过虑的关键词列表,定义如下:
public
sealed
class
KeywordFilterResult
{
public
KeywordFilterResult(
string
result, IEnumerable<Keyword> keywords);
public
string
Result {
get
; }
public
List<Keyword> Keywords {
get
; }
}
|
5.KeywordFilter类,这个类是重点,它是实现过虑的核心,其它类只是功能需求上的辅助成员。要注意的是,它的初始化是需要一定的开销的(关键词量大的时候),所以对于大量的关键词,建议不要使用它的静态方法来进行过虑,而是先初始化实例,再重复的调用实例的方法来过虑。里面还有个方法ContainsAny让你快速判断里面是否包括有关键词。
public
sealed
class
KeywordFilter
{
public
KeywordFilter(IEnumerable<Keyword> keywords);
public
KeywordFilter(IEnumerable<
string
> keywords);
public
KeywordFilter(IEnumerable<Keyword> keywords, IEnumerable<
char
> skipChars);
public
KeywordFilter(IEnumerable<
string
> keywords, IEnumerable<
char
> skipChars);
public
ReadOnlyCollection<Keyword> Keywords {
get
; }
public
ReadOnlyCollection<
char
> SkipChars {
get
; }
public
bool
ContainsAny(
string
original);
public
bool
ContainsAny(
string
original,
bool
ignoreCase);
public
bool
ContainsAny(
string
original, KeywordOrder order);
public
bool
ContainsAny(
string
original, KeywordOrder order,
bool
ignoreCase);
public
KeywordFilterResult Filter(
string
original);
public
KeywordFilterResult Filter(
string
original, KeywordFormatter formatter);
public
KeywordFilterResult Filter(
string
original, KeywordFormatter formatter,
bool
ignoreCase);
public
KeywordFilterResult Filter(
string
original, KeywordFormatter formatter, KeywordOrder order);
public
KeywordFilterResult Filter(
string
original, KeywordFormatter formatter, KeywordOrder order,
bool
ignoreCase);
public
static
KeywordFilterResult Filter(
string
original, IEnumerable<Keyword> keywords);
public
static
KeywordFilterResult Filter(
string
original, IEnumerable<
string
> keywords);
public
static
KeywordFilterResult Filter(
string
original, IEnumerable<Keyword> keywords, KeywordFormatter formatter);
public
static
KeywordFilterResult Filter(
string
original, IEnumerable<
string
> keywords, KeywordFormatter formatter);
public
static
KeywordFilterResult Filter(
string
original, IEnumerable<Keyword> keywords, KeywordFormatter formatter,
bool
ignoreCase);
public
static
KeywordFilterResult Filter(
string
original, IEnumerable<Keyword> keywords, KeywordFormatter formatter, KeywordOrder order);
public
static
KeywordFilterResult Filter(
string
original, IEnumerable<
string
> keywords, KeywordFormatter formatter,
bool
ignoreCase);
public
static
KeywordFilterResult Filter(
string
original, IEnumerable<
string
> keywords, KeywordFormatter formatter, KeywordOrder order);
public
static
KeywordFilterResult Filter(
string
original, IEnumerable<Keyword> keywords, KeywordFormatter formatter, KeywordOrder order,
bool
ignoreCase);
public
static
KeywordFilterResult Filter(
string
original, IEnumerable<
string
> keywords, KeywordFormatter formatter, KeywordOrder order,
bool
ignoreCase);
public
static
KeywordFilterResult Filter(
string
original, IEnumerable<Keyword> keywords, IEnumerable<
char
> skipChars, KeywordFormatter formatter, KeywordOrder order,
bool
ignoreCase);
public
static
KeywordFilterResult Filter(
string
original, IEnumerable<
string
> keywords, IEnumerable<
char
> skipChars, KeywordFormatter formatter, KeywordOrder order,
bool
ignoreCase);
public
static
List<Keyword> LoadKeywords(
string
filePath);
public
static
List<Keyword> LoadKeywords(
string
filePath, Encoding encoding);
public
static
List<Keyword> ParseKeywords(
string
keywordsText);
public
static
void
SaveKeywords(IEnumerable<Keyword> keywords,
string
filePath);
public
static
void
SaveKeywords(IEnumerable<
string
> keywords,
string
filePath);
public
static
void
SaveKeywords(IEnumerable<Keyword> keywords,
string
filePath, Encoding encoding);
public
static
void
SaveKeywords(IEnumerable<
string
> keywords,
string
filePath, Encoding encoding);
}
|
到此,过虑功能成员介绍完了,下面还有两个成员是在KeywordFilter基础上实现的高亮功能HighlightFormatter和Highlighter。
public
sealed
class
HighlightFormatter : KeywordFormatter
{
public
static
readonly
HighlightFormatter Html;
public
HighlightFormatter(
string
prefix,
string
postfix);
public
string
Postfix {
get
; }
public
string
Prefix {
get
; }
public
static
KeywordFormatter Create(
string
prefix,
string
postfix);
public
override
string
Format(
string
keyword);
}
|
public
static
class
Highlighter
{
public
static
string
Highlight(
string
original, IEnumerable<Keyword> keywords, HighlightFormatter formatter);
public
static
string
Highlight(
string
original, IEnumerable<
string
> keywords, HighlightFormatter formatter);
public
static
string
Highlight(
string
original, IEnumerable<Keyword> keywords, HighlightFormatter formatter,
bool
ignoreCase);
public
static
string
Highlight(
string
original, IEnumerable<Keyword> keywords, HighlightFormatter formatter, KeywordOrder order);
public
static
string
Highlight(
string
original, IEnumerable<
string
> keywords, HighlightFormatter formatter,
bool
ignoreCase);
public
static
string
Highlight(
string
original, IEnumerable<
string
> keywords, HighlightFormatter formatter, KeywordOrder order);
public
static
string
Highlight(
string
original, IEnumerable<Keyword> keywords, HighlightFormatter formatter, KeywordOrder order,
bool
ignoreCase);
public
static
string
Highlight(
string
original, IEnumerable<
string
> keywords, HighlightFormatter formatter, KeywordOrder order,
bool
ignoreCase);
}
|
OK,下面开始测试了。
关键词为:"SB|法_轮_功(博客园过虑了)|日-你|日-你大爷"
可跳字符:"▇☆"
原文本:....有博客园要过虑的词,不贴出来了,请看下面的测试结果,最后一组过虑变成了【关键词】,是因为用了自定义的Formatter。
上面只是功能上的测试,下面是1000词/1000字文章/300可跳字符和10000词/10000字文章/300可跳字符性能上的测试结果,可以看到,小量关键词里,KeywordFilter实例化时间很少,但是达到1万关键词时用了252ms,而过虑所用时间只是从前面的0ms变为1ms,关键词达10万时也只用了11ms(本人电脑的配置情况),可见过虑的高效。大家有兴趣的话请下载测试源码来自己看。
是否过虑成功?那是必须的,一词不漏:
高亮在KeywordFilter的基础上就简单实现了,只是实现了个HighlightFormatter,怎么高亮主要看前缀和后缀,下面是测试html高亮的结果: