通用采集小工具重构之路——字符处理规则重构

之前由于工作的原因,写过一个通用网站数据采集的小工具,通过配置XML来采集不同的网站内容。

这段时间工作闲暇之余,觉得有必要重构一下,顺便学习学习,特此记录。

 

字符处理规则重构

字符处理应该算是采集中得一个核心内容,如果在一大串HTML字符串中提取成我们需要的字段。先看看之前的处理方式:

View Code
string temp2;
temp2 = GetStr(str, MyConfig.Url, Lev); //字符截取规则
temp2 = ReplaceStr(temp2, MyConfig.UrlGL, Lev); //字符过滤规则
temp2 = SetCodeing(temp2, MyConfig.UrlBM, Lev);//字符URL编码规则
temp2 = Myreplace(temp2,MyConfig.UrlGvContent,Lev);//字符替换规则

分析毛病:

1. 客户端调用次数太多,如果有四个规则则需要调用四个规则。

2. 扩展不灵活,如果以后遇到新的采集需求而现有的规则不满足要求,需要添加新的规则,则不符合“开闭原则”

 

下面让我们开始重构吧:

1. 提取公用的规则接口

文字处理规则接口
/// <summary>
    /// 文字处理规则接口
    /// </summary>
    public interface ItextRule
    {
        /// <summary>
        /// 字符处理
        /// </summary>
        /// <param name="sourceStr">待处理字符串</param>
        /// <param name="key">配置关键字</param>
        /// <param name="lev">当前层级</param>
        /// <returns></returns>
        string TextPro(string sourceStr,string key,int lev);
    }

2. 建立规则类的抽象类,写入一些公用的方法

字符处理规则基础类
 /// <summary>
    /// 字符处理规则基础类
    /// </summary>
    public abstract class TextRuleBase
    {
        private string myKey = string.Empty;

        public TextRuleBase(string _key)
        {
            myKey = _key;
        }

        /// <summary>
        /// 获取配置文件的值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="lev"></param>
        /// <returns></returns>
        protected string[] GetValue(string key,int lev)
        {
            string str = string.Empty;
            string temp = string.Empty;
            string tempKey = key + myKey + lev;
            bool Istrue = true; 
            while(Istrue) //循环读配置,知道为空
            {
                temp = SiteConfig.ConfigByKey(tempKey);
                if (temp == "")
                {
                    Istrue = false;
                }
                else
                {
                    str += temp + "|";
                    tempKey += lev;
                }
            }

            return str.Split(new char[]{'|'},StringSplitOptions.RemoveEmptyEntries);
            
        }

        /// <summary>
        /// 具体规则处理 强制子类实现
        /// </summary>
        /// <param name="sourceStr"></param>
        /// <param name="Content"></param>
        /// <returns></returns>
        protected abstract string TextPro(string sourceStr, string[] Contents);
       
    }

3. 建立字符规则类,按照上面的逻辑分别建立4个字符规则类,继承接口和抽象类

字符截取规则 基本规则
 /// <summary>
    /// 字符截取规则 基本规则
    /// </summary>
    public class TextIntercept :TextRuleBase, ItextRule
    {
        public TextIntercept():base("")
        {
        }


        #region ItextRule 公开成员
        /// <summary>
        /// 字符截取规则具体实现(多次)
        /// </summary>
        /// <param name="sourceStr"></param>
        /// <param name="key"></param>
        /// <param name="lev"></param>
        /// <returns></returns>
        public string TextPro(string sourceStr, string key, int lev)
        {
            return TextPro(sourceStr,GetValue(key,lev));
        }

        #endregion
       


        #region 内部强制私有方法

        /// <summary>
        /// 字符截取规则具体实现(多次)
        /// </summary>
        /// <param name="sourceStr"></param>
        /// <param name="Content"></param>
        /// <returns></returns>
        protected override string TextPro(string sourceStr, string[] Contents)
        {
            string relText = sourceStr;
            foreach (string value in Contents)
            {
                if (value != "")
                {
                    relText = Function.GetStr(relText, value, MyConfig.Key);
                }
            }

            Console.WriteLine("字符截取规则结果:" + relText);
            Console.WriteLine("");
            return relText;
        }
        #endregion

       
    }

这里就只建立一个示例,其他同。或详见CODE

4. 建立一个高层接口,供客户端直接调用,内部封装好各种规则(根据配置)

字符处理规则的高层接口
  /// <summary>
    /// 字符处理规则的高层接口
    /// </summary>
    public class TextRuleAll:ItextRule
    {
        private Dictionary<string, IList<ItextRule>> ruleList = new Dictionary<string, IList<ItextRule>>();


        #region ItextRule 成员

        public string TextPro(string sourceStr, string key, int lev)
        {
            string dicKey = key + lev;
            string returnStr = string.Empty;
            if (!ruleList.ContainsKey(dicKey))
            {
                IList<ItextRule> list = new List<ItextRule>();

                #region 根据配置构建关键字规则列表
                
                foreach (string vale in MyConfig.AllTextRules())
                {
                    string[] temp = vale.Split('.');
                    string xmlKey = temp[temp.Length - 1];
                    if (xmlKey == "TextIntercept") //写死 字符截取规则为基本规则
                        xmlKey = "";
                    if (SiteConfig.ConfigByKey(key + xmlKey + lev) != "") //XML文件有此配置关键字
                    {
                        list.Add((ItextRule)Assembly.Load("Demo1").CreateInstance(vale));
                 
                    }
                }
                
                #endregion

                ruleList.Add(dicKey,list);
            }

            IList<ItextRule> mylist = ruleList[dicKey];
            if (mylist != null && mylist.Count > 0) //循环执行各种规则处理
            {
                returnStr = sourceStr;
                foreach (ItextRule irule in mylist)
                    returnStr = irule.TextPro(returnStr, key, lev);
            }
            return returnStr;
        }

        #end

5. 配置文件

XML配置
<MyConfig>
    <!--字符处理扩展规则列表-->
    <!--TextIntercept为截取规则-->
    <!--StaticReplace为静态替换规则-->
    <AllTextRules>Collect.TextRule.TextIntercept,Collect.TextRule.StaticReplace,Collect.TextRule.TextUrlEncode,Collect.TextRule.TextFilter</AllTextRules>


    
    <!--TextIntercept截取规则配置-->
    <Name1>邮件地址是[内容]</Name1>
    
    <!--StaticReplacej静态替换配置-->
    <NameStaticReplace1>#,@</NameStaticReplace1>
    <NameStaticReplace11>fuwentao,fwt</NameStaticReplace11>
    
    <!--中文URL编码规则配置-->
    <NameTextUrlEncode1>city=[内容]</NameTextUrlEncode1>
    
    <!--过滤规则配置-->
    <NameTextFilter1>.com,[内容]http</NameTextFilter1>
</MyConfig>

重构完了,让我们再看看客户端的调用:

string testStr = "我是fuwentao,我的邮件地址是fwt1314111#163.com,网址http://www.mywaysoft.net/city=上海";
TextRuleAll cmd = new TextRuleAll();
string rel= cmd.TextPro(testStr, "Name", 1); //结果

就一句cmd.TextPro搞定!是不是比之前简单多了。

并且,这样灵活性也很强,以后如果要增加新的处理规则,则只需要建立一个规则类,然后再配置文件中配置一下就OK啦。

 

DEMO下载

posted @ 2012-06-13 13:30  寒风吹过  阅读(1858)  评论(8编辑  收藏  举报