用C#实现基于查寻字符串的文件行查询器(3)-设计与实现

博客介绍了C#程序设计与实现,先设计SearchEngine.Expression名字空间下的类,完成查询字符串中缀到后缀的转换;接着设计SearchEngine.QueryClass名字空间下的类,完成与、或、非及关键字查询,其中NameQuery类操作文件,其他类在其结果集上运算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者:yxin1322
http://blog.youkuaiyun.com/yxin1322
转载请注明出处

     上面2节我们已经很了解了程序应该具有的功能以及采用的算法,下面我们可以开始设计并实现程序了。

     首先我们要有一些类来完成查询字符串从中缀到后缀的转换,将它们放在SearchEngine.Expression名字空间中:

  • ExpressionEntry 类:用于存储查询串分割后的元素,可以看做一个包含元素值和类型的结构体
  • ExpressionProcess 类:用于将中缀查询串转换成后缀查询串。

     注:ExpressionEntry 类的两个属性分别存查询串元素的值和类型,例如a || b && c可以分割成5个元素:a、||、b、&&和c,分别可以存入5个ExpressionEntry 类的对象中,各对象的值就是元素本身,而它们的类型则分别为string、Or、 string、And、string。之所以要给它们分类,是因为这样可以减少后阶段在对逆波兰式进行运算时的复杂度,具体为什么请读者自己思考。将5个对象放入ArrayList中,形成的集合就可以代表一个表达式,并且中缀与后缀的转换就是改变个元素在集合中的位置。

//ExpressionEntry.cs 

using System;

namespace SearchEngine
{
 namespace Expression
 {
  /// <summary>
  /// ExpressionEntry 的摘要说明。
  /// 类ExpressionEntry用于存储表达式分割后的每一个元素,它有两个字段组成,第一个是元素的值,可以是符号
  /// 或者是字符串,一个是元素的类型,表明它是运算符还是字符串
  /// </summary>
  public class ExpressionEntry
  {
   private string entry_value;//存表达式分离后的各个节点
   private string entry_type;//存表达式分离后的各个节点的类型

   public ExpressionEntry()
   {
    EntryValue=null;
    EntryType=null;
   }

   public ExpressionEntry(string Entryvalue,string Entrytype)
   {
    EntryValue=Entryvalue;
    EntryType=Entrytype;
   }

   public string EntryValue
   {
    get{return entry_value;}
    set{entry_value=value;}
   }
  
   public string EntryType
   {
    get{return entry_type;}
    set{entry_type=value;}
   }
  }
 }
}

//ExpressionProcess.cs

using System;
using System.Collections;
using System.Text.RegularExpressions;

namespace SearchEngine
{
 namespace Expression
 {
  //该类用与处理输入的查询表达式,可以得到查询表达式的中序分割元素集合和后续分割元素集合
  //集合中存储着ExpressionEntry对象
  public class ExpressionProcess
  {
   private string expression;

   public ExpressionProcess()
   {
    Expression=null;
   }

   public ExpressionProcess(string ex)
   {
    Expression=ex;
   }

   public string Expression
   {
    get{return expression;}
    set{expression=value;}
   }

   //返回拆分好的表达式节点集合,属性为中序表达式
   private ArrayList getExpressionEntries()
   {
    ArrayList al=new ArrayList();
    string tem=expression;

    tem=tem.Replace("!"," ! ");//在运算符两边加空格
    tem=tem.Replace("||"," || ");
    tem=tem.Replace("&&"," && ");
    tem=tem.Replace("("," ( ");
    tem=tem.Replace(")"," ) ");

    tem=Regex.Replace(tem,@"/s+"," ");//将多个空格变为一个空格
    tem=tem.Trim();//删除两边的空格

    string [] ExpressionEntries=Regex.Split(tem," ");
    for(int i=0;i<ExpressionEntries.Length;i++)//遍历拆分好的式子,构造表达式节点集合
    {
     if(ExpressionEntries[i].Equals("!"))
     {
      al.Add(new ExpressionEntry(ExpressionEntries[i],"Not"));
     }
     else if(ExpressionEntries[i].Equals("||"))
     {
      al.Add(new ExpressionEntry(ExpressionEntries[i],"Or"));
     }
     else if(ExpressionEntries[i].Equals("&&"))
     {
      al.Add(new ExpressionEntry(ExpressionEntries[i],"And"));
     }
     else if(ExpressionEntries[i].Equals("("))
     {
      al.Add(new ExpressionEntry(ExpressionEntries[i],"Left"));
     }
     else if(ExpressionEntries[i].Equals(")"))
     {
      al.Add(new ExpressionEntry(ExpressionEntries[i],"Right"));
     }
     else if(ExpressionEntries[i].Equals(""))
     {
      ;
     }
     else
     {
      al.Add(new ExpressionEntry(ExpressionEntries[i],"string"));//非逻辑符号的一律视为字符串
     }
    }
    return al;
   }


   //返回拆分好的表达式节点集合,属性为后序表达式,即逆波兰式
   public ArrayList getContradictoryPolandExpressionEntries()
   {
    ArrayList PolandExpression=new ArrayList();//存储逆波兰式
    ArrayList Stack=new ArrayList();//符号栈
   
    Stack.Add(new ExpressionEntry("#","#"));//符号栈底先存垫底符号

    ArrayList Ex=getExpressionEntries();//得到中序节点集合

    for(int i=0;i<Ex.Count;i++)//遍历中序节点集合
    {
     ExpressionEntry ee=(ExpressionEntry)Ex[i];//对每一个节点判断优先关系
     if(ee.EntryType.Equals("Left"))//对左括号的操作
     {
      Stack.Add(ee);
     }
     else if(ee.EntryType.Equals("Right"))//对右括号的操作
     {
      while(!((ExpressionEntry)Stack[Stack.Count-1]).EntryType.Equals("Left") && Stack.Count!=1)
      {
       PolandExpression.Add(Stack[Stack.Count-1]);
       Stack.RemoveAt(Stack.Count-1);
      }
      Stack.RemoveAt(Stack.Count-1);
     }
     else if(ee.EntryType.Equals("Or"))//对或运算符的操作
     {
      while(Stack.Count!=1 && !((ExpressionEntry)Stack[Stack.Count-1]).EntryType.Equals("Left"))
      {
       PolandExpression.Add(Stack[Stack.Count-1]);
       Stack.RemoveAt(Stack.Count-1);
      }
      Stack.Add(ee);
     }
     else if(ee.EntryType.Equals("And"))//对与运算符的操作
     {
      while(((ExpressionEntry)Stack[Stack.Count-1]).EntryType.Equals("And") ||
       ((ExpressionEntry)Stack[Stack.Count-1]).EntryType.Equals("Not"))
      {
       PolandExpression.Add(Stack[Stack.Count-1]);
       Stack.RemoveAt(Stack.Count-1);      
      }
      Stack.Add(ee);
     }
     else if(ee.EntryType.Equals("Not"))//对非运算符的操作
     {
      while(((ExpressionEntry)Stack[Stack.Count-1]).EntryType.Equals("Not"))
      {
       PolandExpression.Add(Stack[Stack.Count-1]);
       Stack.RemoveAt(Stack.Count-1);      
      }
      Stack.Add(ee);
     }
     else //对查询字符串的操作
     {
      PolandExpression.Add(ee);
     }
    }
    while(Stack.Count!=1)//将符号栈的剩余符号放入逆波兰式集合,垫底符号不放入
    {
     PolandExpression.Add(Stack[Stack.Count-1]);
     Stack.RemoveAt(Stack.Count-1);
    }
    return PolandExpression; //返回逆波兰式
   }


   //打印表达式节点集合,可以是中序集合也可以是后序集合
   public static void PrintExpressionEntries(ArrayList ExpressionEntriesList,int Mode)
   {
    if(Mode==0)
    {
     for(int i=0;i<ExpressionEntriesList.Count;i++)
     {
      System.Console.WriteLine("{0,9} : {1}",((ExpressionEntry)ExpressionEntriesList[i]).EntryType,
       ((ExpressionEntry)ExpressionEntriesList[i]).EntryValue);
     }
    }
    else
    {
     System.Console.Write("/n尼波兰表达式:");
     for(int i=0;i<ExpressionEntriesList.Count;i++)
     {
      System.Console.Write("{0} ",((ExpressionEntry)ExpressionEntriesList[i]).EntryValue);
     }
     System.Console.WriteLine("/n");
    }
   }
  }
 }
}

     接下来我们要设计几个类来分别完成与(AndQuery)、或(OrQuery)、非(NotQuery)的查询,如果一次查询中即没有与,也没有或和非的运算,只有一个关键字,那么我们称之为关键字查询(NameQuery),将这些类放在SearchEngine.QueryClass名字空间中,并都继承自同一个基类Query:

  • Query 类:作为所有查询类的基类,定义了一个查询结果集,一个查询结果集打印函数以及一个所有派生类必须独自实现的抽象函数Search( )。
  • NameQuery 类:用于“关键字”查询,继承自Query类,拥有Query的成员和方法。
  • AndQuery 类:用于“与”查询,继承自Query类,拥有Query的成员和方法。
  • OrQuery 类:用于“或”查询,继承自Query类,拥有Query的成员和方法。
  • NotQuery 类:用于“非”查询,继承自Query类,拥有Query的成员和方法。
  • SearchResultCompare 类:为了使查询结果集中的SearchResultEntry类对象能够在ArrayList中排序,定此类并实现IComparer接口。SearchResultEntry类存储着查询的结果,每一个SearchResultEntry类的对象存储一条满足查询条件的记录,该类将在后面详细描述。

//Query.cs

using System;
using System.Collections;

namespace SearchEngine
{
 namespace QueryClass
 {
  /// <summary>
  /// Query 的摘要说明。
  /// 作为查询类的基类
  /// </summary>
  public abstract class Query
  {
   private ArrayList search_results;//用于存储查询结果

   public Query()
   {
    search_results=new ArrayList();
   }

   public ArrayList SearchResults//属性
   {
    get
    {
     ArrayList al=(ArrayList)search_results.Clone();
     return al;
    }
    set
    {
     search_results=(ArrayList)value.Clone();
    }
   }

   public abstract void Search();//抽象函数

   public void PrintSearchResult()
   {
    System.Console.WriteLine("查询结果:共找到{0}条记录。",this.SearchResults.Count);
    System.Console.WriteLine("----------------------------------------------------------------------");
    for(int i=0;i<this.SearchResults.Count;i++)
    {
     SearchResultEntry sre=(SearchResultEntry)SearchResults[i];
     System.Console.WriteLine("[{0,2}]:{1}",sre.LineNumber,sre.LineStr);
    }
    System.Console.WriteLine("----------------------------------------------------------------------");
   }

  }
 }
}

//NameQuery.cs

using System;
using System.Collections;
using System.IO;

namespace SearchEngine
{
 namespace QueryClass
 {
  /// <summary>
  /// NameQuery 的摘要说明。
  /// 单关键字查询类
  /// </summary>
  public class NameQuery:Query
  {
   private string keyword;//存储查询关键字
   private string filename;//存储文件名


   //默认构造函数
   public NameQuery():base()
   {
    KeyWord="";
    FileName="";
   }

   //带参数的构造函数
   public NameQuery(string key,string fn):base()
   {
    KeyWord=key;
    filename=fn;

    this.Search();//初始化完毕立即搜索
   }

   //属性
   public string KeyWord
   {
    set{keyword=value;}
    get{return keyword;}
   }

   //属性
   public string FileName
   {
    set{filename=value;}
    get{return filename;}
   }

   //重写Search函数:将包含有keyword的行写入结果集合
   public override void Search()
   {
    if(this.FileName=="" || this.KeyWord=="")//如果文件未指定或关键字未指定
    {
     System.Console.WriteLine("查询关键字或查询目标未设置");
     return;
    }
    if(!File.Exists(FileName))//如果文件不存在
    {
     System.Console.WriteLine("待查询的目标文件不存在!");
     return ;
    }

    ArrayList result=new ArrayList();
    StreamReader sr=File.OpenText(FileName);
    string tem=sr.ReadLine();
    int i=1;
    while(tem!=null)
    {
     if(tem.IndexOf(KeyWord)!=-1)
      result.Add(new SearchResultEntry(i,tem));
     tem=sr.ReadLine();
     i++;
    }
    sr.Close();
    this.SearchResults=result;
   }

  }
 }
}

//AndQuery.cs

using System;
using System.Collections;

namespace SearchEngine
{
 namespace QueryClass
 {
  /// <summary>
  /// AndQuery 的摘要说明。
  /// “与”查询类
  /// </summary>
  public class AndQuery:Query
  {
   private ArrayList param1;//存储第一个结果集参数
   private ArrayList param2;//存储第二个结果结参数

   //默认构造函数
   public AndQuery():base()
   {
    param1=new ArrayList();
    param2=new ArrayList();
   }

   //带参构造函数
   public AndQuery(Query q1,Query q2):base()
   {
    param1=q1.SearchResults;
    param2=q2.SearchResults;

    this.Search();
   }


   public ArrayList Param1//属性
   {
    get
    {
     ArrayList al=(ArrayList)param1.Clone();
     return al;
    }
    set
    {
     param1=(ArrayList)value.Clone();
    }
   }

   public ArrayList Param2//属性
   {
    get
    {
     ArrayList al=(ArrayList)param2.Clone();
     return al;
    }
    set
    {
     param2=(ArrayList)value.Clone();
    }
   }

   public override void Search()
   {
    ArrayList result=new ArrayList();
    
    for(int i=0;i<this.Param1.Count;i++)
    {
     for(int j=0;j<this.Param2.Count;j++)
     {
      if(((SearchResultEntry)Param1[i]).LineNumber==((SearchResultEntry)Param2[j]).LineNumber)
       result.Add((SearchResultEntry)Param1[i]);
     }
    }

    result.Sort(new SearchResultCompare());//将结果按照行号排序

    this.SearchResults=result;//将结果写入最终结果
   }
  }
 }
}

//OrQuery.cs

using System;
using System.Collections;

namespace SearchEngine
{
 namespace QueryClass
 {
  /// <summary>
  /// OrQuery 的摘要说明。
  /// “或”查询类
  /// </summary>
  public class OrQuery:Query
  {
   private ArrayList param1;//存储第一个结果集参数
   private ArrayList param2;//存储第二个结果结参数

   //默认构造函数
   public OrQuery():base()
   {
    param1=new ArrayList();
    param2=new ArrayList();
   }

   //带参构造函数
   public OrQuery(Query q1,Query q2):base()
   {
    param1=q1.SearchResults;
    param2=q2.SearchResults;

    this.Search();
   }


   public ArrayList Param1//属性
   {
    get
    {
     ArrayList al=(ArrayList)param1.Clone();
     return al;
    }
    set
    {
     param1=(ArrayList)value.Clone();
    }
   }

   public ArrayList Param2//属性
   {
    get
    {
     ArrayList al=(ArrayList)param2.Clone();
     return al;
    }
    set
    {
     param2=(ArrayList)value.Clone();
    }
   }

   //
   public override void Search()
   {
    ArrayList result=new ArrayList();
    
    int sign=0;
    for(int i=0;i<this.Param1.Count;i++)
    {
     for(int j=0;j<this.Param2.Count;j++)
     {
      if(((SearchResultEntry)Param1[i]).LineNumber==((SearchResultEntry)Param2[j]).LineNumber)
       sign=1;
     }
     if(sign==0)
     {
      result.Add((SearchResultEntry)Param1[i]);
     }
     sign=0;
    }
    for(int k=0;k<this.Param2.Count;k++)
    {
     result.Add((SearchResultEntry)Param2[k]);
    }

    result.Sort(new SearchResultCompare());//将结果按照行号排序

    this.SearchResults=result;//将结果写入最终结果
   }
  }
 }
}

//NotQuery.cs

using System;
using System.Collections;
using System.IO;

namespace SearchEngine
{
 namespace QueryClass
 {
  /// <summary>
  /// NotQuery 的摘要说明。
  /// 取反查询的类
  /// </summary>
  public class NotQuery:Query
  {
   private ArrayList unNotResult;
   private string filename;//存储文件名

   public NotQuery():base()
   {
    UnNotResult=new ArrayList();
    FileName="";
   }

   //带参数的构造函数
   public NotQuery(Query q,string file_name):base()
   {
    UnNotResult=q.SearchResults;
    filename=file_name;

    this.Search();//初始化完毕立即搜索
   } 

   public ArrayList UnNotResult//属性
   {
    get
    {
     ArrayList al=(ArrayList)unNotResult.Clone();
     return al;
    }
    set
    {
     unNotResult=(ArrayList)value.Clone();
    }
   }

   //属性
   public string FileName
   {
    set{filename=value;}
    get{return filename;}
   }

   //重写Search函数:将不含有keyword的行写入结果集合
   public override void Search()
   {
    if(this.FileName=="")//如果文件未指定或关键字未指定
    {
     System.Console.WriteLine("查询文件未设置");
     return;
    }
    if(!File.Exists(FileName))//如果文件不存在
    {
     System.Console.WriteLine("待查询的目标文件不存在!");
     return ;
    }

    ArrayList result=new ArrayList();//结果集合
    StreamReader sr=File.OpenText(FileName);
    string tem=sr.ReadLine();
    int i=1;//行号
    int sign=0;//判定当前行是否出现在参数结果集中的标志,如果当前行出现在参数结果集中,sign置1
    while(tem!=null)//遍历文件所有行
    {
     for(int j=0;j<this.UnNotResult.Count;j++)
     {
      if(((SearchResultEntry)UnNotResult[j]).LineNumber==i)//当发现当前行与参数结果集重复,置标志sign
       sign=1;
     }
     if(sign==0)//如果标志未置1,则将当前行加如结果集合
     {
      result.Add(new SearchResultEntry(i,tem));
     }
     sign=0;//标志未重新置为0

     tem=sr.ReadLine();
     i++;
    }
    sr.Close();
    this.SearchResults=result;//将结果写入最终结果
   }
  }
 }
}

//SearchResultCompare.cs

using System;
using System.Collections;

namespace SearchEngine
{
 namespace QueryClass
 {
  /// <summary>
  /// SearchResultCompare 的摘要说明。
  /// 为了SearchResultEntry能够在ArrayList中排序,特实现IComparer接口
  /// </summary>
  public class SearchResultCompare:System.Collections.IComparer
  {
   public int Compare(Object x,Object y)
   {
    return ((SearchResultEntry)x).LineNumber-((SearchResultEntry)y).LineNumber;
   }
  }
 }
}

注:以上查询类中真正操作了文件的只是NameQuery类,它负责从文件中找出含有关键字的行,并生成SearchResultCompare对象存入结果集合,而其他查询类,诸如AndQuery、OrQuery、NotQuery等类只是在多个NameQuery的查询结果集上进行以、或、非的运算。

注:以上查询类中真正操作了文件的只是NameQuery类,它负责从文件中找出含有关键字的行,并生成SearchResultCompare对象存入结果集合,而其他查询类,诸如AndQuery、OrQuery、NotQuery等类只是在多个NameQuery的查询结果集上进行以、或、非的运算。

注:以上查询类中真正操作了文件的只是NameQuery类,它负责从文件中找出含有关键字的行,并生成SearchResultCompare对象存入结果集合,而其他查询类,诸如AndQuery、OrQuery、NotQuery等类只是在多个NameQuery的查询结果集上进行以、或、非的运算。

注:以上查询类中真正操作了文件的只是NameQuery类,它负责从文件中找出含有关键字的行,并生成SearchResultCompare对象存入结果集合,而其他查询类,诸如AndQuery、OrQuery、NotQuery等类只是在多个NameQuery的查询结果集上进行以、或、非的运算。

注:以上查询类中真正操作了文件的只是NameQuery类,它负责从文件中找出含有关键字的行,并生成SearchResultCompare对象存入结果集合,而其他查询类,诸如AndQuery、OrQuery、NotQuery等类只是在多个NameQuery的查询结果集上进行以、或、非的运算。

注:以上查询类中真正操作了文件的只是NameQuery类,它负责从文件中找出含有关键字的行,并生成SearchResultCompare对象存入结果集合,而其他查询类,诸如AndQuery、OrQuery、NotQuery等类只是在多个NameQuery的查询结果集上进行以、或、非的运算。

核心的类已经实现,接下来就是定义测试类将他们有机地结合起来,成为一个整体。
类列表如下:
  • SearchText类:该类的每个对象绑定一个文件,并对文件进行查询操作。
  • SearchResultEntry类:该类存储查询到的结果信息,每个SearchResultEntry对象存储一条查询结果,每个SearchResultEntry包括两个部分,第一部分为结果的行号,第二部分为结果的内容。
  • SearchDoor类:定义程序的主函数。
//SearchText.cs
using System;
using System.Collections;
using SearchEngine.QueryClass;
using SearchEngine.Expression;
namespace SearchEngine
{
 /// <summary>
 /// 该类提供了搜索文件的类实现
 /// 搜索文件的类
 /// </summary>
 public class SearchText
 {
  private string file_name;
  private ArrayList expression_entries;
  
  public SearchText()
  {
   FileName="";
   ExpressionEntries=new ArrayList();
  }
  public SearchText(string filename,ArrayList expressionEntries)
  {
   FileName=filename;
   ExpressionEntries=(ArrayList)expressionEntries.Clone();
  }
  public string FileName
  {
   set{file_name=value;}
   get{return file_name;}
  }
  public ArrayList ExpressionEntries
  {
   set{expression_entries=(ArrayList)value.Clone();}
   get
   {
    ArrayList al=(ArrayList)expression_entries.Clone();
    return al;
   }
  }
  public ArrayList getSearchResult()
  {
   if(this.FileName=="")
   {
    System.Console.WriteLine("没有指定查询的文件!");
    return null;
   }
   if(this.expression_entries.Count==0)
   {
    System.Console.WriteLine("查询字符串为空!");
    return null;
   }
   ArrayList expression=this.ExpressionEntries;
   ArrayList Stack=new ArrayList();
   for(int i=0;i<expression.Count;i++)
   {
    ExpressionEntry ee=(ExpressionEntry)expression[i];
    if(ee.EntryType.Equals("string"))
    {
     Stack.Add(new NameQuery(ee.EntryValue,this.FileName));
    }
    else if(ee.EntryType.Equals("And"))
    {
     if(Stack.Count<2)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q1=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Query q2=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new AndQuery(q1,q2));
    }
    else if(ee.EntryType.Equals("Or"))
    {
     if(Stack.Count<2)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q1=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Query q2=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new OrQuery(q1,q2));
    }
    else if(ee.EntryType.Equals("Not"))
    {
     if(Stack.Count<1)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new NotQuery(q,this.FileName));
    }
    else
    {
     System.Console.WriteLine("表达式出现异常!");
     return null;
    }
   }
   if(Stack.Count!=1)
   {
    System.Console.WriteLine("表达式语法出错,请检查!");
    return null;
   }
   return ((Query)Stack[0]).SearchResults;
  }
  public static void PrintSearchResult(ArrayList Result)
  {
   System.Console.WriteLine("查询结果:共找到{0}条记录。",Result.Count);
   System.Console.WriteLine("----------------------------------------------------------------------");
   for(int i=0;i<Result.Count;i++)
   {
    SearchResultEntry sre=(SearchResultEntry)Result[i];
    System.Console.WriteLine("[{0,2}]:{1}",sre.LineNumber,sre.LineStr);
   }
   System.Console.WriteLine("----------------------------------------------------------------------/n/n");
  }
 }
}

核心的类已经实现,接下来就是定义测试类将他们有机地结合起来,成为一个整体。
类列表如下:
  • SearchText类:该类的每个对象绑定一个文件,并对文件进行查询操作。
  • SearchResultEntry类:该类存储查询到的结果信息,每个SearchResultEntry对象存储一条查询结果,每个SearchResultEntry包括两个部分,第一部分为结果的行号,第二部分为结果的内容。
  • SearchDoor类:定义程序的主函数。
//SearchText.cs
using System;
using System.Collections;
using SearchEngine.QueryClass;
using SearchEngine.Expression;
namespace SearchEngine
{
 /// <summary>
 /// 该类提供了搜索文件的类实现
 /// 搜索文件的类
 /// </summary>
 public class SearchText
 {
  private string file_name;
  private ArrayList expression_entries;
  
  public SearchText()
  {
   FileName="";
   ExpressionEntries=new ArrayList();
  }
  public SearchText(string filename,ArrayList expressionEntries)
  {
   FileName=filename;
   ExpressionEntries=(ArrayList)expressionEntries.Clone();
  }
  public string FileName
  {
   set{file_name=value;}
   get{return file_name;}
  }
  public ArrayList ExpressionEntries
  {
   set{expression_entries=(ArrayList)value.Clone();}
   get
   {
    ArrayList al=(ArrayList)expression_entries.Clone();
    return al;
   }
  }
  public ArrayList getSearchResult()
  {
   if(this.FileName=="")
   {
    System.Console.WriteLine("没有指定查询的文件!");
    return null;
   }
   if(this.expression_entries.Count==0)
   {
    System.Console.WriteLine("查询字符串为空!");
    return null;
   }
   ArrayList expression=this.ExpressionEntries;
   ArrayList Stack=new ArrayList();
   for(int i=0;i<expression.Count;i++)
   {
    ExpressionEntry ee=(ExpressionEntry)expression[i];
    if(ee.EntryType.Equals("string"))
    {
     Stack.Add(new NameQuery(ee.EntryValue,this.FileName));
    }
    else if(ee.EntryType.Equals("And"))
    {
     if(Stack.Count<2)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q1=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Query q2=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new AndQuery(q1,q2));
    }
    else if(ee.EntryType.Equals("Or"))
    {
     if(Stack.Count<2)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q1=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Query q2=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new OrQuery(q1,q2));
    }
    else if(ee.EntryType.Equals("Not"))
    {
     if(Stack.Count<1)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new NotQuery(q,this.FileName));
    }
    else
    {
     System.Console.WriteLine("表达式出现异常!");
     return null;
    }
   }
   if(Stack.Count!=1)
   {
    System.Console.WriteLine("表达式语法出错,请检查!");
    return null;
   }
   return ((Query)Stack[0]).SearchResults;
  }
  public static void PrintSearchResult(ArrayList Result)
  {
   System.Console.WriteLine("查询结果:共找到{0}条记录。",Result.Count);
   System.Console.WriteLine("----------------------------------------------------------------------");
   for(int i=0;i<Result.Count;i++)
   {
    SearchResultEntry sre=(SearchResultEntry)Result[i];
    System.Console.WriteLine("[{0,2}]:{1}",sre.LineNumber,sre.LineStr);
   }
   System.Console.WriteLine("----------------------------------------------------------------------/n/n");
  }
 }
}

核心的类已经实现,接下来就是定义测试类将他们有机地结合起来,成为一个整体。
类列表如下:
  • SearchText类:该类的每个对象绑定一个文件,并对文件进行查询操作。
  • SearchResultEntry类:该类存储查询到的结果信息,每个SearchResultEntry对象存储一条查询结果,每个SearchResultEntry包括两个部分,第一部分为结果的行号,第二部分为结果的内容。
  • SearchDoor类:定义程序的主函数。
//SearchText.cs
using System;
using System.Collections;
using SearchEngine.QueryClass;
using SearchEngine.Expression;
namespace SearchEngine
{
 /// <summary>
 /// 该类提供了搜索文件的类实现
 /// 搜索文件的类
 /// </summary>
 public class SearchText
 {
  private string file_name;
  private ArrayList expression_entries;
  
  public SearchText()
  {
   FileName="";
   ExpressionEntries=new ArrayList();
  }
  public SearchText(string filename,ArrayList expressionEntries)
  {
   FileName=filename;
   ExpressionEntries=(ArrayList)expressionEntries.Clone();
  }
  public string FileName
  {
   set{file_name=value;}
   get{return file_name;}
  }
  public ArrayList ExpressionEntries
  {
   set{expression_entries=(ArrayList)value.Clone();}
   get
   {
    ArrayList al=(ArrayList)expression_entries.Clone();
    return al;
   }
  }
  public ArrayList getSearchResult()
  {
   if(this.FileName=="")
   {
    System.Console.WriteLine("没有指定查询的文件!");
    return null;
   }
   if(this.expression_entries.Count==0)
   {
    System.Console.WriteLine("查询字符串为空!");
    return null;
   }
   ArrayList expression=this.ExpressionEntries;
   ArrayList Stack=new ArrayList();
   for(int i=0;i<expression.Count;i++)
   {
    ExpressionEntry ee=(ExpressionEntry)expression[i];
    if(ee.EntryType.Equals("string"))
    {
     Stack.Add(new NameQuery(ee.EntryValue,this.FileName));
    }
    else if(ee.EntryType.Equals("And"))
    {
     if(Stack.Count<2)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q1=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Query q2=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new AndQuery(q1,q2));
    }
    else if(ee.EntryType.Equals("Or"))
    {
     if(Stack.Count<2)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q1=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Query q2=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new OrQuery(q1,q2));
    }
    else if(ee.EntryType.Equals("Not"))
    {
     if(Stack.Count<1)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new NotQuery(q,this.FileName));
    }
    else
    {
     System.Console.WriteLine("表达式出现异常!");
     return null;
    }
   }
   if(Stack.Count!=1)
   {
    System.Console.WriteLine("表达式语法出错,请检查!");
    return null;
   }
   return ((Query)Stack[0]).SearchResults;
  }
  public static void PrintSearchResult(ArrayList Result)
  {
   System.Console.WriteLine("查询结果:共找到{0}条记录。",Result.Count);
   System.Console.WriteLine("----------------------------------------------------------------------");
   for(int i=0;i<Result.Count;i++)
   {
    SearchResultEntry sre=(SearchResultEntry)Result[i];
    System.Console.WriteLine("[{0,2}]:{1}",sre.LineNumber,sre.LineStr);
   }
   System.Console.WriteLine("----------------------------------------------------------------------/n/n");
  }
 }
}

核心的类已经实现,接下来就是定义测试类将他们有机地结合起来,成为一个整体。
类列表如下:
  • SearchText类:该类的每个对象绑定一个文件,并对文件进行查询操作。
  • SearchResultEntry类:该类存储查询到的结果信息,每个SearchResultEntry对象存储一条查询结果,每个SearchResultEntry包括两个部分,第一部分为结果的行号,第二部分为结果的内容。
  • SearchDoor类:定义程序的主函数。
//SearchText.cs
using System;
using System.Collections;
using SearchEngine.QueryClass;
using SearchEngine.Expression;
namespace SearchEngine
{
 /// <summary>
 /// 该类提供了搜索文件的类实现
 /// 搜索文件的类
 /// </summary>
 public class SearchText
 {
  private string file_name;
  private ArrayList expression_entries;
  
  public SearchText()
  {
   FileName="";
   ExpressionEntries=new ArrayList();
  }
  public SearchText(string filename,ArrayList expressionEntries)
  {
   FileName=filename;
   ExpressionEntries=(ArrayList)expressionEntries.Clone();
  }
  public string FileName
  {
   set{file_name=value;}
   get{return file_name;}
  }
  public ArrayList ExpressionEntries
  {
   set{expression_entries=(ArrayList)value.Clone();}
   get
   {
    ArrayList al=(ArrayList)expression_entries.Clone();
    return al;
   }
  }
  public ArrayList getSearchResult()
  {
   if(this.FileName=="")
   {
    System.Console.WriteLine("没有指定查询的文件!");
    return null;
   }
   if(this.expression_entries.Count==0)
   {
    System.Console.WriteLine("查询字符串为空!");
    return null;
   }
   ArrayList expression=this.ExpressionEntries;
   ArrayList Stack=new ArrayList();
   for(int i=0;i<expression.Count;i++)
   {
    ExpressionEntry ee=(ExpressionEntry)expression[i];
    if(ee.EntryType.Equals("string"))
    {
     Stack.Add(new NameQuery(ee.EntryValue,this.FileName));
    }
    else if(ee.EntryType.Equals("And"))
    {
     if(Stack.Count<2)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q1=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Query q2=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new AndQuery(q1,q2));
    }
    else if(ee.EntryType.Equals("Or"))
    {
     if(Stack.Count<2)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q1=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Query q2=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new OrQuery(q1,q2));
    }
    else if(ee.EntryType.Equals("Not"))
    {
     if(Stack.Count<1)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new NotQuery(q,this.FileName));
    }
    else
    {
     System.Console.WriteLine("表达式出现异常!");
     return null;
    }
   }
   if(Stack.Count!=1)
   {
    System.Console.WriteLine("表达式语法出错,请检查!");
    return null;
   }
   return ((Query)Stack[0]).SearchResults;
  }
  public static void PrintSearchResult(ArrayList Result)
  {
   System.Console.WriteLine("查询结果:共找到{0}条记录。",Result.Count);
   System.Console.WriteLine("----------------------------------------------------------------------");
   for(int i=0;i<Result.Count;i++)
   {
    SearchResultEntry sre=(SearchResultEntry)Result[i];
    System.Console.WriteLine("[{0,2}]:{1}",sre.LineNumber,sre.LineStr);
   }
   System.Console.WriteLine("----------------------------------------------------------------------/n/n");
  }
 }
}

核心的类已经实现,接下来就是定义测试类将他们有机地结合起来,成为一个整体。
类列表如下:
  • SearchText类:该类的每个对象绑定一个文件,并对文件进行查询操作。
  • SearchResultEntry类:该类存储查询到的结果信息,每个SearchResultEntry对象存储一条查询结果,每个SearchResultEntry包括两个部分,第一部分为结果的行号,第二部分为结果的内容。
  • SearchDoor类:定义程序的主函数。
//SearchText.cs
using System;
using System.Collections;
using SearchEngine.QueryClass;
using SearchEngine.Expression;
namespace SearchEngine
{
 /// <summary>
 /// 该类提供了搜索文件的类实现
 /// 搜索文件的类
 /// </summary>
 public class SearchText
 {
  private string file_name;
  private ArrayList expression_entries;
  
  public SearchText()
  {
   FileName="";
   ExpressionEntries=new ArrayList();
  }
  public SearchText(string filename,ArrayList expressionEntries)
  {
   FileName=filename;
   ExpressionEntries=(ArrayList)expressionEntries.Clone();
  }
  public string FileName
  {
   set{file_name=value;}
   get{return file_name;}
  }
  public ArrayList ExpressionEntries
  {
   set{expression_entries=(ArrayList)value.Clone();}
   get
   {
    ArrayList al=(ArrayList)expression_entries.Clone();
    return al;
   }
  }
  public ArrayList getSearchResult()
  {
   if(this.FileName=="")
   {
    System.Console.WriteLine("没有指定查询的文件!");
    return null;
   }
   if(this.expression_entries.Count==0)
   {
    System.Console.WriteLine("查询字符串为空!");
    return null;
   }
   ArrayList expression=this.ExpressionEntries;
   ArrayList Stack=new ArrayList();
   for(int i=0;i<expression.Count;i++)
   {
    ExpressionEntry ee=(ExpressionEntry)expression[i];
    if(ee.EntryType.Equals("string"))
    {
     Stack.Add(new NameQuery(ee.EntryValue,this.FileName));
    }
    else if(ee.EntryType.Equals("And"))
    {
     if(Stack.Count<2)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q1=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Query q2=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new AndQuery(q1,q2));
    }
    else if(ee.EntryType.Equals("Or"))
    {
     if(Stack.Count<2)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q1=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Query q2=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new OrQuery(q1,q2));
    }
    else if(ee.EntryType.Equals("Not"))
    {
     if(Stack.Count<1)
     {
      System.Console.WriteLine("表达式语法出错,请检查!");
      return null;
     }
     Query q=(Query)Stack[Stack.Count-1];
     Stack.RemoveAt(Stack.Count-1);
     Stack.Add(new NotQuery(q,this.FileName));
    }
    else
    {
     System.Console.WriteLine("表达式出现异常!");
     return null;
    }
   }
   if(Stack.Count!=1)
   {
    System.Console.WriteLine("表达式语法出错,请检查!");
    return null;
   }
   return ((Query)Stack[0]).SearchResults;
  }
  public static void PrintSearchResult(ArrayList Result)
  {
   System.Console.WriteLine("查询结果:共找到{0}条记录。",Result.Count);
   System.Console.WriteLine("----------------------------------------------------------------------");
   for(int i=0;i<Result.Count;i++)
   {
    SearchResultEntry sre=(SearchResultEntry)Result[i];
    System.Console.WriteLine("[{0,2}]:{1}",sre.LineNumber,sre.LineStr);
   }
   System.Console.WriteLine("----------------------------------------------------------------------/n/n");
  }
 }
}

//SearchResultEntry.cs
using System;
namespace SearchEngine
{
 /// <summary>
 /// SearchResultEntry 的摘要说明。
 /// 该类存储查询到的结果信息,每个SearchResultEntry对象存储一条查询结果
 /// 每个SearchResultEntry包括两个部分,第一部分为结果的行号,第二部分为结果的内容
 /// </summary>
 public class SearchResultEntry
 {
  private int line_number;
  private string line_str;
  //默认构造函数
  public SearchResultEntry()
  {
   LineNumber=-1;
   LineStr=null;
  }
  //带参构造函数
  public SearchResultEntry(int ln,string ls)
  {
   LineNumber=ln;
   LineStr=ls;
  }
  //line_number属性
  public int LineNumber
  {
   get{return line_number;}
   set{line_number=value;}
  }
  //line_str属性
  public string LineStr
  {
   get{return line_str;}
   set{line_str=value;}
  }
 }
}

//SearchDoor.cs
using System;
using System.Collections;
using SearchEngine.Expression;
using SearchEngine.QueryClass;
using System.IO;
namespace SearchEngine
{
 //该类用做程序入口
 public class SearchDoor
 {
  public static void Main()
  {
   System.Console.WriteLine("                ----------------------------------------------                        ");
   System.Console.WriteLine("                                文件行搜索引擎                           /n");
   System.Console.WriteLine("                   1.支持与、或、非组合      2.支持括号嵌套   ");
   System.Console.WriteLine("                ----------------------------------------------                        ");
   System.Console.WriteLine("                 运行环境:Microsoft .Net FrameWork                ");
   System.Console.WriteLine("                ----------------------------------------------                        ");
   System.Console.Write("-请输入文件路径及文件名:");
   
   String FileName=System.Console.ReadLine();
   while(!File.Exists(FileName))
   {
    System.Console.WriteLine("-你指定的文件不存在,请重新指定!/n");
    System.Console.Write("-请输入文件路径及文件名:");
    FileName=System.Console.ReadLine();
   }
   while(true)
   {
    System.Console.Write("/n-请输入查询串(支持括号):");
    string QueryString=System.Console.ReadLine();
    ExpressionProcess ep=new ExpressionProcess(QueryString);
    ArrayList expression=ep.getContradictoryPolandExpressionEntries();
    ExpressionProcess.PrintExpressionEntries(expression,1);
    SearchText st=new SearchText(FileName,expression);
    ArrayList ResultSet=st.getSearchResult();
    if(ResultSet!=null)
     SearchText.PrintSearchResult(ResultSet);
   }
  }
 }
}
        以上是基于查寻字符串的文件行查询器的C#全部代码及说明。
        说实话,在做这个实验之前,刚看到题目,就把我吓到了,因为程序涉及到编译原理的内容,又要用我刚刚学习的新语言c#来实现,对自己是否能最终完成程序一点底也没有。于是一点一点看书补充知识,试着一个功能一个功能地实现,慢慢发现其实也不是很难。最终我用两天时间完成了这个程序,自己感觉有很大的收获:
        1.面向对象的程序设计中,类的层次非常重要,需要遵循的规则是高内聚和低耦合,每个类都有自己的功能,公用的功能应该放在他们的父类中。程序编码前应该仔细分析程序的结构,我原来认为每个查询类都要查询和操作文件,经过仔细分析,发现只要NameQuery类操作文件就可以了,其他的查询类只是在操作NameQuery类的查询结果集,搞清楚了这一点,使我少走了许多弯路。

        2.面向对象设计方法中的继承可以使设计的类在概念与实现上有层次关系,多态的实质是方法的调用在执行期动态决定,如果多个类继承自一个父类,那么其父类的对象可以用它的子类的构造函数来构造,换句话说就是父类的指针可以指向并操作子类的对象,利用这一特性,我们在设计方法时,如果将参数的类型定义为父类的类型,那么将其子类的对象作为参数传入都是合法的,这样就不需要为每个子类都单独定义一个函数。
        无论如何,我的第一步是迈出了,程序虽然很小,但一定还存在着许多逻辑的错误和设计上的不足,还请读过我文章的朋友能够留言给予指正,我都将虚心接受。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值