Ejemplo n.º 1
0
        /// <summary>
        /// 处理中文量词
        /// </summary>
        /// <param name="context"></param>
        private void ProcessQuant(AnalyzeContext context)
        {
            if (!NeedQuantScan(context))    // 如果不需要量词扫描,则直接返回
            {
                return;
            }

            if (context.CurrentCharType == CharUtil.CHAR_CHINESE)
            {
                if (_hits.Count > 0)     // 如果前面积累了一些尚未成形的量词,则优先处理这些
                {
                    var hits = _hits.ToArray();
                    _hits.Clear();                  // 先清空,然后再保存那些本轮尚未处理掉的未成形量词(比如新的尚未成形的量词)
                    for (int i = 0; i < hits.Length; i++)
                    {
                        var hit = hits[i];
                        hit = DictTrie.Instance.MatchWithHit(context.CharBuff, context.Cursor, hit);
                        if (hit.IsMatch)     // 当前尚未成形的量词 hit 加上 context.Cursor 开始的若干字符形成一个成形的量词
                        {
                            var lex = new Lexeme(context.BuffOffset, hit.Begin, context.Cursor - hit.Begin + 1, Lexeme.TYPE_CN_QUANT);
                            context.AddLexeme(lex);
                            if (hit.IsPrefix)   // 这个新成形的量词如果同时还是某个量词的前缀,则添加到 hit 列表(最大化匹配)
                            {
                                _hits.Add(hit);
                            }
                        }
                        else if (hit.IsPrefix)  // 当前尚未成形的量词 hit 加上 context.Cursor 开始的若干字符形成某个量词的前缀,则添加到 hit 列表
                        {
                            _hits.Add(hit);
                        }
                    }
                }
                // 除了与前面的尚未成形的量词进行联合,context.Cursor开始的字符另外还需要单字匹配,以发现更多可能的量词
                var singleHit = DictTrie.Instance.MatchWithQuantDict(context.CharBuff, context.Cursor, 1);
                if (singleHit.IsMatch)   // 首字成量词
                {
                    // 输出此单字量词
                    var lex = new Lexeme(context.BuffOffset, context.Cursor, 1, Lexeme.TYPE_CN_QUANT);
                    context.AddLexeme(lex);

                    if (singleHit.IsPrefix)     // 如果当前单字同时还是另一个量词的前缀
                    {
                        _hits.Add(singleHit);
                    }
                }
                else if (singleHit.IsPrefix)     // 当前单字虽未独立成量词,但是是另一个量词的前缀
                {
                    _hits.Add(singleHit);
                }
            }
            else    // 当前字符不是中文字符,则清空未成形的量词,因为已经不可能成量词了
            {
                _hits.Clear();
            }

            if (context.IsBuffConsumed())   // 如果缓冲区已经读取完毕
            {
                _hits.Clear();              // 清空尚未成形的量词,因为已经没机会成量词了
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// 处理中文数词
        /// </summary>
        /// <param name="context"></param>
        private void ProcessNum(AnalyzeContext context)
        {
            if (_start == -1 && _end == -1)      // 当前尚未开始处理中文数词
            {
                if (context.CurrentCharType == CharUtil.CHAR_CHINESE && _cnNums.Contains(context.CurrentChar))
                {
                    _end = _start = context.Cursor;     // 如果遇到中文数词,记录起始位置
                }
            }
            else
            {
                if (context.CurrentCharType == CharUtil.CHAR_CHINESE && _cnNums.Contains(context.CurrentChar))
                {
                    _end = context.Cursor;          // 继续匹配到中文数词,更新结束位置
                }
                else
                {
                    // 中文数词结束,输出词元
                    var lex = new Lexeme(context.BuffOffset, _start, _end - _start + 1, Lexeme.TYPE_CN_NUM);
                    context.AddLexeme(lex);
                    _end = _start = -1;
                }
            }

            if (context.IsBuffConsumed())    // 缓冲区如果读取完毕
            {
                if (_start != -1 && _end != -1)
                {
                    // 当前仍在处理中文数词,那么输出词元
                    var lex = new Lexeme(context.BuffOffset, _start, _end - _start + 1, Lexeme.TYPE_CN_NUM);
                    context.AddLexeme(lex);
                    _end = _start = -1;
                }
            }
        }
Ejemplo n.º 3
0
 /// <summary>
 /// 判断是否需要扫描量词
 /// </summary>
 /// <param name="context"></param>
 /// <returns>是否需要扫描量词</returns>
 private bool NeedQuantScan(AnalyzeContext context)
 {
     // 如果当前正在处理中文数词,或者仍有带处理量词 hit
     if ((_start != -1 && _end != -1) || _hits.Count > 0)
     {
         return(true);
     }
     else
     {
         // 紧邻当前的上一个词元
         if (context.RawLexemes.Size > 0)
         {
             var lex = context.RawLexemes.PeekLast();
             // 如果是中文数词,或者是阿拉伯数词
             if (Lexeme.TYPE_CN_NUM == lex.Type || Lexeme.TYPE_ARABIC == lex.Type)
             {
                 // 如果上一个词元与当前正要处理的字符无缝连接,且没有重叠
                 if (lex.Begin + lex.Length == context.Cursor)
                 {
                     return(true);
                 }
             }
         }
     }
     return(false);
 }
Ejemplo n.º 4
0
        private void Init()
        {
            DictTrie.Init(_cfg);
            _context    = new AnalyzeContext(_cfg);
            _arbitrator = new IKArbitrator();

            _segmenters = new List <ISegment>(3);
            _segmenters.Add(new EnglishSegmenter());
            _segmenters.Add(new CNQuantSegmenter());
            _segmenters.Add(new CJKSegmenter());
        }
Ejemplo n.º 5
0
 public void Analyze(AnalyzeContext context)
 {
     ProcessNum(context);
     ProcessQuant(context);
     if (_start == -1 && _end == -1 && _hits.Count == 0)     // 如果当前数量词处理完毕,且没有待成量词的hit,则释放占用的缓冲区
     {
         context.UnlockBuffer(SEGMENTER_NAME);
     }
     else
     {
         context.LockBuffer(SEGMENTER_NAME);
     }
 }
Ejemplo n.º 6
0
        public void Analyze(AnalyzeContext context)
        {
            // 当前是处理完状态还是正在处理中状态
            // 注意处理的顺序,ProcessMix必须第一处理
            var flag = ProcessMix(context) || ProcessEnglish(context) || ProcessArabic(context);

            if (flag)
            {
                context.LockBuffer(SEGMENTER_NAME);
            }
            else
            {
                context.UnlockBuffer(SEGMENTER_NAME);
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// 分词歧义处理
        /// </summary>
        /// <param name="context"></param>
        /// <param name="useSmart"></param>
        public void Process(AnalyzeContext context, bool useSmart)
        {
            var lexs = context.RawLexemes;      // 原始词元

            var lex         = lexs.PollFirst();
            var overlapPath = new LexemePath();

            while (lex != null)
            {
                // lex没有添加进overlapPath,此时 overlapPath.Size > 0
                if (!overlapPath.ExpandOverlapLexeme(lex))
                {
                    if (overlapPath.Size == 1 || !useSmart)     // 词元链中只有一个词元,或者不使用智能分词时,不进行歧义处理,直接添加到context中
                    {
                        context.AddLexemePath(overlapPath);
                    }
                    else                                        // 否则,进行歧义处理
                    {
                        // overlapPath.Size > 1
                        var head      = overlapPath.Head;
                        var judgePath = Judge(head, overlapPath.PathSpan);
                        context.AddLexemePath(judgePath);
                    }

                    overlapPath = new LexemePath();
                    overlapPath.ExpandOverlapLexeme(lex);
                }
                lex = lexs.PollFirst();
            }

            // 退出循环后最后再处理 overlapPath
            if (overlapPath.Size == 1 || !useSmart)
            {
                context.AddLexemePath(overlapPath);
            }
            else
            {
                var head = overlapPath.Head;
                context.AddLexemePath(Judge(head, overlapPath.PathSpan));
            }
        }
Ejemplo n.º 8
0
 /// <summary>
 /// 处理英文或者数字组成的混合词元
 /// </summary>
 /// <param name="context"></param>
 /// <returns>当前是否是处理完状态还是正在处理中状态</returns>
 private bool ProcessMix(AnalyzeContext context)
 {
     if (_start == -1)    // 当前分词器尚未开始处理混合词元
     {
         if (CharUtil.CHAR_ARABIC == context.CurrentCharType || CharUtil.CHAR_ENGLISH == context.CurrentCharType)
         {
             _end = _start = context.Cursor;
         }
     }
     else
     {
         // 如果是英文字符或者是数字字符
         if (CharUtil.CHAR_ARABIC == context.CurrentCharType || CharUtil.CHAR_ENGLISH == context.CurrentCharType)
         {
             _end = context.Cursor;          // 更新混合词元的结束位置
         }
         // 如果是英文连接符
         else if (CharUtil.CHAR_USELESS == context.CurrentCharType && IsLetterConnector(context.CurrentChar))
         {
             _end = context.Cursor;
         }
         else
         {
             // 非有效英文或数字字符
             var lex = new Lexeme(context.BuffOffset, _start, _end - _start + 1, Lexeme.TYPE_ALPHANUM);
             context.AddLexeme(lex);
             _end = _start = -1;
         }
     }
     if (context.IsBuffConsumed())
     {
         if (_start != -1 && _end != -1)
         {
             var lex = new Lexeme(context.BuffOffset, _start, _end - _start + 1, Lexeme.TYPE_ALPHANUM);
             context.AddLexeme(lex);
             _end = _start = -1;
         }
     }
     return(_start != -1 || _end != -1);
 }
Ejemplo n.º 9
0
        /// <summary>
        /// 处理数字词元
        /// </summary>
        /// <param name="context"></param>
        /// <returns>当前是否是处理完状态还是正在处理中状态</returns>
        private bool ProcessArabic(AnalyzeContext context)
        {
            if (_arabicStart == -1)      // 当前分词器尚未开始处理数字字符
            {
                if (context.CurrentCharType == CharUtil.CHAR_ARABIC)
                {
                    _arabicEnd = _arabicStart = context.Cursor;
                }
            }
            else                        // 当前分词器正在处理数字字符
            {
                if (context.CurrentCharType == CharUtil.CHAR_ARABIC)
                {
                    _arabicEnd = context.Cursor;
                }
                else if (context.CurrentCharType == CharUtil.CHAR_USELESS && IsNumConnector(context.CurrentChar))
                {
                    // 遇到数字之间的有效分隔符
                }
                else
                {   // 遇到非数字字符,输出数字词元
                    var lex = new Lexeme(context.BuffOffset, _arabicStart, _arabicEnd - _arabicStart + 1, Lexeme.TYPE_ARABIC);
                    context.AddLexeme(lex);
                    _arabicEnd = _arabicStart = -1;
                }
            }

            if (context.IsBuffConsumed())
            {
                if (_arabicStart != -1 && _arabicEnd != -1)
                {
                    var lex = new Lexeme(context.BuffOffset, _arabicStart, _arabicEnd - _arabicStart + 1, Lexeme.TYPE_ARABIC);
                    context.AddLexeme(lex);
                    _arabicEnd = _arabicStart = -1;
                }
            }

            return(_arabicStart != -1 || _arabicEnd != -1);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// 处理英文词元
        /// </summary>
        /// <param name="context"></param>
        /// <returns>当前是否是处理完状态还是正在处理中状态</returns>
        private bool ProcessEnglish(AnalyzeContext context)
        {
            if (_englishStart == -1)       // 当前分词器尚未开始处理英文字符
            {
                if (context.CurrentCharType == CharUtil.CHAR_ENGLISH)
                {
                    _englishStart = context.Cursor;
                    _englishEnd   = _englishStart;
                }
            }
            else
            {
                if (context.CurrentCharType == CharUtil.CHAR_ENGLISH)
                {
                    _englishEnd = context.Cursor;
                }
                else            // 遇到非英文字符,则输出英文词元
                {
                    var lex = new Lexeme(context.BuffOffset, _englishStart, _englishEnd - _englishStart + 1, Lexeme.TYPE_ENGLISH);
                    context.AddLexeme(lex);
                    _englishEnd = _englishStart = -1;
                }
            }

            if (context.IsBuffConsumed())                     // 如果缓冲区内容读取完毕
            {
                if (_englishStart != -1 && _englishEnd != -1) // 如果当前正在处理英文词元
                {
                    var lex = new Lexeme(context.BuffOffset, _englishStart, _englishEnd - _englishStart + 1, Lexeme.TYPE_ENGLISH);
                    context.AddLexeme(lex);
                    _englishEnd = _englishStart = -1;
                }
            }

            return(_englishStart != -1 || _englishEnd != -1);    // 返回是否需要锁定缓冲区
        }