SCWS是国人做的一个很优秀的分词库,它的php扩展可以方便地处理中文分词。现在发现其中一个函数scws_get_words
函数的问题,这个函数是用来获取分词结果的,其第二个参数可以指定你需要返回的结果,这是它的c api文档描述(php大同小异)
·scws_top_t scws_get_words(scws_t s, char *xattr);
描述:返回指定词性的关键词表,系统会根据词语出现的先后插入列表。参数 xattr 用来描述要排除
或参与的统计词汇词性,多个词性之间用逗号隔开。当以~开头时表示统计结果中不包含这些词性,
否则表示必须包含,传入 NULL 表示统计全部词性。
返回值:返回词表集链表的头指针,该词表集必须调用 scws_free_tops 释放
错误:无
也就是说我只需要在第二个参数里加上以逗号分割的参数即可,比如我加上'~Ag,~a,~ad,~b,~c,~Dg,~d,~e'
字符,表示我要在结果中过滤掉这些。
但实际的结果是,无论你加了多少过滤条件都不起作用,但相反,如果你只加一个过滤条件比如'~a'
,也就是没有逗号的时候,它可以把相应的结果过滤掉。所以我考虑这之中是否存在bug。下面附上此函数的c实现代码,大家帮我看看
// get words by attr (rand order)
scws_top_t scws_get_words(scws_t s, char *xattr)
{
int off, cnt, xmode = SCWS_NA;
xtree_t xt;
scws_res_t res, cur;
scws_top_t top, tail, base;
char *word;
word_attr *at = NULL;
if (!s || !s->txt || !(xt = xtree_new(0,1)))
return NULL;
__PARSE_XATTR__;
// save the offset.
off = s->off;
s->off = 0;
base = tail = NULL;
while ((cur = res = scws_get_result(s)) != NULL)
{
do
{
/* check attribute filter */
if (at != NULL)
{
if ((xmode == SCWS_NA) && !_attr_belong(cur->attr, at))
continue;
if ((xmode == SCWS_YEA) && _attr_belong(cur->attr, at))
continue;
}
/* put to the stats */
if (!(top = xtree_nget(xt, s->txt + cur->off, cur->len, NULL)))
{
top = (scws_top_t) malloc(sizeof(struct scws_topword));
top->weight = cur->idf;
top->times = 1;
top->next = NULL;
top->word = (char *)_mem_ndup(s->txt + cur->off, cur->len);
strncpy(top->attr, cur->attr, 2);
// add to the chain
if (tail == NULL)
base = tail = top;
else
{
tail->next = top;
tail = top;
}
xtree_nput(xt, top, sizeof(struct scws_topword), s->txt + cur->off, cur->len);
}
else
{
top->weight += cur->idf;
top->times++;
}
}
while ((cur = cur->next) != NULL);
scws_free_result(res);
}
// free at & xtree
if (at != NULL)
free(at);
xtree_free(xt);
// restore the offset
s->off = off;
return base;
}
我发现它的__PARSE_XATTR__
宏有些问题啊,这里另外附上word_attr
的结构定义
/* macro to parse xattr -> xmode, at */
#define __PARSE_XATTR__ do { \
if (xattr == NULL) break; \
if (*xattr == '~') { xattr++; xmode = SCWS_YEA; } \
if (*xattr == '\0') break; \
cnt = ((strlen(xattr)/2) + 2) * sizeof(word_attr); \
at = (word_attr *) malloc(cnt); \
memset(at, 0, cnt); \
cnt = 0; \
for (cnt = 0; (word = strchr(xattr, ',')); cnt++) { \
strncpy(at[cnt], xattr, 2); \
xattr = word + 1; \
} \
strncpy(at[cnt], xattr, 2); \
} while (0)
typedef char word_attr[4];
这样处理xattr的话,只能处理词性是2个字符的情况,因为它strncpy(at[cnt], xattr, 2);
。这也太马虎了吧,词性表里有一堆一个字符的词性啊,它copy的话就会把逗号也copy进去啊。
自己全部用2个字符的词性过滤试了一下,果然可以了。。。大家考虑下这里应该怎么改下吧