zoukankan      html  css  js  c++  java
  • WEBUS2.0 In Action

    最近由于工作的需要, 要分析大量C#代码, 在数万个cs文件中搜索特定关键词. 这是一项非常耗时的工作, 用Notepad++要运行接近半个小时. 于是我利用WEBUS2.0 SDK创建了一个代码搜索器程序, 非常方便的完成了这项工作.

    Code Search程序首先会在选定的目录中搜索所有cs文件:

        private void btnOpen_Click(object sender, EventArgs e)
            {
                try
                {
                    if (folderBrowserDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        Task.Factory.StartNew(IndexProc);
                        //...
            }

    然后创建IIndexer, 并在一个线程中为所有找到的文件编制索引:

            void IndexProc()
            {
                var files = Directory.GetFiles(folderBrowserDialog1.SelectedPath, "*.cs", SearchOption.AllDirectories);
                if (files != null && files.Length > 0)
                {
                    //...this.ResetIndex();
                    foreach (var file in files)
                    {
                        Document doc = new Document();
                        doc.Fields.Add(new Field("FileName", file, FieldAttributes.None));
                        doc.Fields.Add(new Field("Code", StringHelper.LoadString(file), FieldAttributes.AnalyseIndex));
                        m_Index.Add(doc);
                        //...
                    }
                }
                //...
            }
    
            void ResetIndex()
            {
                if (m_Index != null)
                {
                    m_Index.Close();
                }
                m_Index = new IndexManager(new CodeAnalyzer());
                m_Index.DumpDocs = 3000;
                m_Index.DumpSize = 10;
                m_Index.MinIndexSize = int.MaxValue;
                m_Index.MaxIndexSize = int.MaxValue;
                m_Index.MergeFactor = int.MaxValue;
                m_Index.New(AppDomain.CurrentDomain.BaseDirectory + @"Index");
                m_Searcher = new IndexSearcher(m_Index);
            }

    通过调节DumpDocs和DumpSize, 可以优化程序的内存占用;

    通过调节Min/MaxIndexSize和MergeFactor, 可以优化程序的IO性能, 目前我设置的MinIndexSize最大意味着自始至终只会生成一个索引片段; MergeFactor最大意味着从不合并索引片段.

    在创建索引的时候, 我们使用的是专门为代码分析设计的IAnalyzer:

        class CodeAnalyzer : IAnalyzer
        {
            //...public ITokenStream GetTokenStream(Webus.Documents.Field field)
            {
                if (field.Name == "Code")
                {
                    return this.GetTokenStream(field.Value.ToString());
                }
                else
                {
                    return null;
                }
            }
        }
    
        class CodeTokenStream : ITokenStream
        {
            HashSet<string> stops = new HashSet<string>(new string[] { 
                "abstract",
                "event",    
                "new",    
                //... 
                "enum",    
                "namespace",    
                "string"
            });
            Queue<Token> m_Buffer = new Queue<Token>();
            public CodeTokenStream(string text)
            {
                MatchCollection mc = Regex.Matches(text, @"w+");
                foreach (Match m in mc)
                {
                    var key = m.Value.ToLower();
                    if (stops.Contains(key) == false)
                    {
                        m_Buffer.Enqueue(new Token(key, m.Index, m.Length));
                    }
                }
            }
            //...
    }

    这个分析器中包含了所有C#的关键词, 由于他们是绝对高频词并且没有搜索的意义, 因此在分析的时候会跳过这些词汇而不做任何处理. 

    在编制索引的时候通过事件将状态更新到UI上面:

            private void frmCodeSearch_Load(object sender, EventArgs e)
            {
                try
                {
                    this.StatusChanged += new StatusChangeEventHandler(frmCodeSearch_StatusChanged);
                    //...
            }
    
            delegate void UpdateUI();
            void frmCodeSearch_StatusChanged(object sender, string status)
            {
                this.Invoke(new UpdateUI(() => { this.txtStatus.Text = status; }));
            }

    这里是跨线程更新UI, 因此需要使用this.Invoke来封送相应操作. 

    索引编制过程中就可以开始搜索了:

    对应代码如下:

            private void txtKeyword_TextChanged(object sender, EventArgs e)
            {
                try
                {
                    TermQuery query = new TermQuery(new Term("Code", txtKeyword.Text.ToLower()));
                    var hits = m_Searcher.Search(query);
                    List<SearchResult> result = new List<SearchResult>();
                    foreach (HitDoc hit in hits)
                    {
                        StandardHighlighter hl = new StandardHighlighter(hit);
                        result.Add(new SearchResult(hit));
                    }
                    dgvResult.DataSource = result;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ExceptionHelper.ToString(ex));
                }
            }

    创建一个TermQuery对象, 对Code字段进行搜索, 构建List<SearchResult>类型的结果集, 并且绑定到DataGridView上面, 大功告成! enjoy~!

    下载源代码

    阅读更多WEBUS2.0 SDK文章

    2013-7-21补充: 

    增强了搜索功能, 支持WEBUS2.0 SDK的查询表达式, 能够完成各种复杂的搜索任务. 具体语法将在后面的文章中介绍. 

    2013-8-20补充: 

    Build - 选择一个文件夹开始编制索引, 编好的索引自动保存在当前目录的CodeSearch.Index子目录下面. 比如我们选择C:SourceCode来编制索引, 这索引数据会保存在C:SourceCodeCodeSearch.Index中. 

    Open - 打开已经存在的索引, 即上面所说的CodeSearch.Index文件夹. 

    关闭程序时会自动关闭当前索引. 索引关闭后全部数据都保存到磁盘上, 下次可以直接打开来继续使用. 

  • 相关阅读:
    C语言学习11(循环结构:for语句)
    C语言学习9(循环结构:while语句)
    C语言学习8(选择结构的嵌套)
    C语言学习笔记2
    C语言学习笔记1
    C语言的学习5(数据的输出)
    C语言学习12(函数的定义)
    第二十一章流 14临时文件 简单
    第二十一章流 12输出数据到文件指定位置处seekp() 简单
    第二十一章流 11指定读取文件中的数据seekg() 简单
  • 原文地址:https://www.cnblogs.com/iamzyf/p/3199434.html
Copyright © 2011-2022 走看看