示例#1
0
        /// <summary>
        /// 使用用户词典合并粗分结果,并将结果收集到全词图中,然后返回合并后的结果
        /// In place modify
        /// </summary>
        /// <param name="vertices"></param>
        /// <param name="wordNet"></param>
        /// <returns></returns>
        protected static List <Vertex> CombineByCustomDict(List <Vertex> vertices, WordNet wordNet)
        {
            var list = CombineByCustomDict(vertices);       // 合并,产生 最长匹配
            int line = 0;                                   // 行号

            //! 索引
            for (int i = 0; i < list.Count; i++)
            {
                var vertex    = list[i];                    // 当前词条
                var parentLen = vertex.realWord.Length;     // 当前词条的字符串长度
                int currLine  = line;                       // 获取当前行号
                if (parentLen >= 3)                         // 长词条,
                {
                    Action <int, int, WordAttr> action = (begin, end, value) =>
                    {
                        if (end - begin == parentLen)
                        {
                            return;
                        }
                        wordNet.Add(currLine + begin, new Vertex(vertex.realWord.Substring(begin, end), value));
                    };
                    CustomDictionary.Parse(vertex.realWord, action);
                }
                line += parentLen;
            }
            return(list);
        }
        /// <summary>
        /// 生成一元词网
        /// </summary>
        /// <param name="wordNet">初创词网对象</param>
        protected void GenerateWordNet(WordNet wordNet)
        {
            var chars = wordNet.charArr;                               // 原始句子的字符数组

            var searcher = CoreDictionary._trie.GetSearcher(chars, 0); // 获取核心词典词语搜索器:搜索核心词典中的词条

            while (searcher.Next())
            {
                // searcher.begin + 1 -> 由于存在起始辅助节点,所以每个节点的索引向后偏移 1 。
                wordNet.Add(searcher.begin + 1, new Vertex(new string(chars, searcher.begin, searcher.length), searcher.value, searcher.index));
            }

            var vertices = wordNet.Vertices;

            // 上一步中,仅仅是根据核心词典中的词条来划分原始句子,所以还需要对句子中除了核心词汇之外的部分进行分词
            // 比如“这是一个操蛋的世界”,假设核心词汇为“一个”、“世界”,那显然剩余部分——“这是”、“操蛋的”——还需要进行分词处理
            // 然而,我们这里先使用快速原子分词,后面再进一步使用专用分词器分词
            for (int i = 1; i < vertices.Length;)
            {
                if (vertices[i].Count == 0)     // 如果当前行没有顶点
                {
                    int j = i + 1;              // 往后遍历,找到下一个存在节点的行
                    for (; j < vertices.Length - 1; j++)
                    {
                        if (vertices[j].Count != 0)
                        {
                            break;
                        }
                    }
                    wordNet.Add(i, QuickAtomSegment(chars, i - 1, j - 1)); // i-1,j-1,这里因为有起始辅助节点,导致下标 i,j 均向后偏移一位,所以需要减去 1。
                    i = j;                                                 // 更新当前位置到下一个有节点的行号位置
                }
                else
                {
                    i += vertices[i].Last().realWord.Length;
                }
            }
        }
示例#3
0
        /// <summary>
        /// 合并数量词
        /// </summary>
        /// <param name="list"></param>
        /// <param name="wordNet"></param>
        /// <param name="config"></param>
        protected void CombineNumQuant(List <Vertex> list, WordNet wordNet, SegConfig config)
        {
            if (list.Count < 4)
            {
                return;                     // 除去首尾辅助节点2个,还需要至少2个有效节点才能合并
            }
            var sb   = new StringBuilder();
            int line = 1;                   // 初始化为1,跳过起始辅助节点

            for (int i = 0; i < list.Count; i++)
            {
                var pre = list[i];
                if (pre.HasNature(Nature.m))     // 第一个数词出现
                {
                    sb.Append(pre.realWord);
                    Vertex cur = null;
                    i++;
                    while (i < list.Count)      // 遍历数词之后的词
                    {
                        cur = list[i];
                        if (cur.HasNature(Nature.m))        // 连续数词
                        {
                            sb.Append(cur.realWord);
                            list[i] = null;
                            RemoveFromWordNet(cur, wordNet, line, sb.Length);
                            i++;
                        }
                        else
                        {
                            break;
                        }
                    }
                    if (cur != null)                                                                         // 合并连续的数词后,遇到的第一个非数词
                    {
                        if (cur.HasNature(Nature.q) || cur.HasNature(Nature.qv) || cur.HasNature(Nature.qt)) // cur 是量词
                        {
                            if (config.indexMode)                                                            // 如果开启索引(最小)分词模式,则先将连续数词作为一个节点添加进词网
                            {
                                wordNet.Add(line, new Vertex(sb.ToString(), new WordAttr(Nature.m)));
                            }

                            sb.Append(cur.realWord);        // 合数量词
                            list[i] = null;
                            RemoveFromWordNet(cur, wordNet, line, sb.Length);
                        }
                        else                                // 遇到第一个非数词,也非量词
                        {
                            line += cur.realWord.Length;    // 更新行号,表示跳过这个(非数非量)词
                        }
                    }

                    if (sb.Length != pre.realWord.Length)                                  // 长度不等,意味着合并到连续数词或者数量词
                    {
                        foreach (var vertex in wordNet.GetRow(line + pre.realWord.Length)) // 遍历第一个数词之后的行号上的所有节点列表,将这些节点的前驱节点置为空
                        {
                            vertex.from = null;
                        }
                        pre.realWord = sb.ToString();       // 首个数词修改为连续数词 或者 数量词
                        pre.word     = TAG_NUMBER;          // 实际上,本项目将数量词等同数词处理了
                        pre.attr     = new WordAttr(Nature.mq);
                        pre.wordId   = CoreDictionary.M_WORD_ID;
                        sb.Clear();
                    }
                }

                sb.Clear();
                line += pre.realWord.Length;            // 更新行号,跳过合并后的数量词
            }
        }