老杂毛博客
  青青子衿,悠悠我心。但为君故,沉吟至今。
博客首页 | 人生历程 | 编程开发 | 机关门  
  文章分类
 
博客首页 > 软件网络编程 > 文章正文

正则表达式替换链接,将网址做成跳转,替换成空链接的方法

2009/12/5 10:34:29
 

    当你的网站有会员发布信息功能的时候,就会是一件非常头疼的事情,刚开始做的小网站一但被会员在文章中加入大量的链接,这对于网站优化工作是非常不利的,我们通常的做法就是将链接去掉,或将链接替换成空链接,这方面的文章在网上也有很多,但是讲的都不是很详细,今天周六,我就抽时间写一篇详细的教程。

我们要完成这样的工作必须要用正则表达式来完成,所以我们先要导入一个名字空间
using System.Text.RegularExpressions;

第一个问题:将文章中的链接去掉

    首先我写了这样一个方法:
    public static string StrReplace(string contentsStr, string pattern, string replaceStr)
    {
            return Regex.Replace(contentsStr, pattern, replaceStr, RegexOptions.IgnoreCase);
    }
    很多人都知道string有一个Replace方法,确不知道regex也有一个这样的方法,string的replace方法只可以完全替换,而regex的replace则比string的强大的多,可以用正则表达式去匹配一些模糊的数据然后在替换。

    我写的这个方法有三个参数,第一个参数contentsStr是你文章的源字符串,第二个pattern是你的正则表达式字符串,第三个replaceStr是你要替换成的字符串。

    OK,那么如果我们要把文章中的链接全部替换掉怎么调用这个方法呢,我们首先要写正则表达式,我已经写好了,  #lt;a.*?#gt;  这个正则表达式可以把源代码中的a标记整个提取出来,不管里面有什么style还是title或href属性,这个表达式可以匹配这样的字符:

#lt;a href="aa"#gt;
#lt;a href="aa" style="font-size:12px;"#gt;
#lt;a href="aa" style="font-size:12px;" title="aaa"#gt;

那么我们这样调用这个方法就可以了

contentsStr=StrReplace(contentsStr,"#lt;a.*?#gt;","");

OK,这样我们就链接的前半边替换掉了,然后我们不要忘了,a标记的返回标记,这个用string的replace就可以替换了。
contentsStr=contentsStr.Replace("#lt;/a#gt;","");

至此我们的链接基本就全部清空了。

第二个问题:将链接替换成空链接

    我在写文章之前去网上搜索了一下,很多的写法,不过感觉都特别的乱,可以说是乱做一团,正则表达式也是

复杂的要命,其实根本没必要那么费力,我们只需要把上面的方法的调用方法简单的改一下就行了。

contentsStr=StrReplace(contentsStr,"#lt;a.*?#gt;","#lt;a href=\"#\"#gt;");

    怎么样,这样行不行,一定行的,我们做事要多动一动脑子,很简单的一个替换就解决了,干嘛搞得那么复杂

    不过我这样写这个代码有一个问题,那就是当文章中的链接应用了样式,我这样就全替换掉了,现在的空链接

是应用的默认样式,好,现在就给你解决这个问题。

第三个问题:将链接替换成其它网址或空链接

    下面大家先来看一个正则表达式:(?s)#lt;a[\s][^#gt;]*href\s*=\s*[\""\']?(?#lt;url#gt;([^\""\'#gt;\s]*))[\""\']?[^#gt;]*#gt;(?#lt;title#gt;([^#lt;]+|.*?)?)#lt;/a\s*#gt;

     这个正则号称是可以提取页面中所有的链接,包含单引号的或双引号的和没有引号的。

     这确实是一个问题,因为现在的html标记写的都不是很标准,网址用单引号和双引号以及不用引号都可以,所以我们的正则表达式也不是特别好写,我在网上搜索了半天也没有找到一个合适的正则,全都是匹配双引号的,遇到没有引号的和单引号的就匹配不出来了。

     上面那个正则不是我写的,也是在一个牛人的博客里看到的,不过那不是我想要的,我自己写了一个简单的正则:href=\s*[\"']?([^\"'#gt;]*)\s*[\"']?
  
     用这个正则就可以把页面中a标记的链接全部提取出来了。

     为了方便菜鸟学习,我把提取链接的方法也粘出来,代码如下:

        /// #lt;summary#gt;
        /// 提取页面的超级链接或其它指定字符返回ArrayList
        /// #lt;/summary#gt;
        /// #lt;param name="StrCode"#gt;源字符串#lt;/param#gt;
        /// #lt;param name="strRegex"#gt;正则表达式#lt;/param#gt;
        /// #lt;returns#gt;#lt;/returns#gt;
        public static ArrayList GetHyperLinks(string StrCode, string strRegex)
        {
            ArrayList al = new ArrayList();

            Regex r = new Regex(strRegex, RegexOptions.IgnoreCase);
            MatchCollection m = r.Matches(StrCode);

            for (int i = 0; i #lt;= m.Count - 1; i++)
            {
                bool rep = false;
                string strNew = m[i].ToString();

                // 过滤重复的URL
                foreach (string str in al)
                {
                    if (strNew == str)
                    {
                        rep = true;
                        break;
                    }
                }

                if (!rep) al.Add(strNew);
            }
            al.Sort();
            return al;
        }

       我们建立一个arraylist然后把上面的正则传到这个方法里,返回的就是这个页面中所有a标记中的链接了,哈哈,好,我来调用一下。

            ArrayList hrefStr = new ArrayList();
            hrefStr =GetHyperLinks(str, @"href=\s*[\"']?([^\"'#gt;]*)\s*[\"']?");

       在这里我要说明另一个问题,如果你不是想替换成空链接,那就用自己网站中页面转接的方法来解决这个问题,比如我TV150的网站,我想用href.tv150.cn这个域名给页面中的链接做跳转。

比如我页面中出现了www.baidu.com 这样的链接,那么我不给他替换成空,我给他替换成http://href.tv150.cn/?url=http://www.baidu.com

       这样的话,链接还是可以打开的,但是对于网站优化影响不大,所以这种方法很好,嘿嘿。
       哦,对了,在告诉你一个更完美的地方,如果你是本网站的链接那就不要替换,那岂不是更人性化。所以在代码中加入判断

       我的代码:if (updateUrl.IndexOf("tv150.cn") #lt; 0)  如果是tv150的内部链接,那就不替换了,哈哈,还为自己站内链接做了优化,真是不错啊。

       如果你要替换成空,那就直接替换成#好了,一点也不影响其它的属性。


       好了,关于网页中链接的问题基本已经全说完了,有问题在下面给我留言,我看到后会挑着我会的回答的。 : )

谢谢大家关注我的文章,本文由老杂毛原创,转载请务必注明此版权信息。

 

2009年12月6日新修订

      经过近两天的观察发现以上代码有一个缺陷,当一个内容代码字符串中包含了两个同样的网址,而只有一个杠的区别的时候,如:

http://www.tv150.cn 和 http://www.tv150.cn/  这两个网址其实是一个,但是以上的那个提取链接方法却并没有把这两个合并,而是当成了两个网址来处理,这样的话,就导致同样一个网址被替换两次,如果是跳转的话,就是两次跳转,所以说是非常不合理的,于是今天我把代码加以改进,代码如下:

        /// #lt;summary#gt;
        /// 提取页面的超级链接或其它指定字符返回ArrayList
        /// #lt;/summary#gt;
        /// #lt;param name="StrCode"#gt;源字符串#lt;/param#gt;
        /// #lt;param name="strRegex"#gt;正则表达式#lt;/param#gt;
        /// #lt;returns#gt;#lt;/returns#gt;
        public static ArrayList GetHyperLinks(string StrCode, string strRegex)
        {
            ArrayList al = new ArrayList();

            Regex r = new Regex(strRegex, RegexOptions.IgnoreCase);
            MatchCollection m = r.Matches(StrCode);

            for (int i = 0; i #lt;= m.Count - 1; i++)
            {
                bool rep = false;
                string strNew = m[i].ToString().Trim();

                //如果网址后面有斜杠用此方法替换
                if (strNew.Length #gt; 3)
                {
                    string lastStrif = strNew.Substring(strNew.Length - 1, 1);
                    if (lastStrif == "/")//判断最后一个字符是否为/
                    {
                        strNew = strNew.Substring(0, strNew.Length - 1);
                    }
                    else
                    {
                        if (lastStrif == "\"" || lastStrif == "'")
                        {
                            strNew = strNew.Substring(0, strNew.Length - 1);
                            if (strNew.Substring(strNew.Length - 1, 1) == "/")
                            {
                                strNew = strNew.Substring(0, strNew.Length - 1);
                            }
                        }
                    }
                }
                //替换结束

                // 过滤重复的URL
                foreach (string str in al)
                {
                    if (strNew == str)
                    {
                        rep = true;
                        break;
                    }
                }

                if (!rep) al.Add(strNew);
            }
            al.Sort();
            return al;
        }

    在方法的中间加上了这么一段代码:

                //如果网址后面有斜杠用此方法替换
                if (strNew.Length #gt; 3)
                {
                    string lastStrif = strNew.Substring(strNew.Length - 1, 1);
                    if (lastStrif == "/")//判断最后一个字符是否为/
                    {
                        strNew = strNew.Substring(0, strNew.Length - 1);
                    }
                    else
                    {
                        if (lastStrif == "\"" || lastStrif == "'")
                        {
                            strNew = strNew.Substring(0, strNew.Length - 1);
                            if (strNew.Substring(strNew.Length - 1, 1) == "/")
                            {
                                strNew = strNew.Substring(0, strNew.Length - 1);
                            }
                        }
                    }
                }
                //替换结束

 

代码解释:用这段代码来判断最后一个字符是不是/ 因为我的正则表达式也是匹配单引号和双引号的,所以如果倒数第一个字符不是的话,还要去判断倒数第二个。

截取判断的前提是提取的内容一定要大于2或3,不然的话会报错,所以加上了if (strNew.Length #gt; 3) 判断。

OK,这样的话,同一个网址就不会被替换两次了,好了就这样,如果再遇到其它问题我会在这篇文章中继续修改代码。

阅读: (3144)  评论(6)  
 
网友评论:
 
 1.匿名网友2009/12/6 18:07:44 
讲的很详细,谢谢啦。
 2.匿名网友2010/4/16 18:56:50 
讲的非常好,支持一下
 3.匿名网友2010/9/20 16:36:43 
.............有必要研究研究
 4.2016/5/13 21:15:27 
 
相关文章:
 微信支付asp.net V3.3.7 sys
 ERRORLOG 文件太大的处理办法
 Attempted to read or w
 Ctrl键自动按下,Ctrl键和Alt总感觉
 解决 Your project contai
 adb install 多设备id号一样,如
 如何去掉优酷,土豆等网站的广告?
 webview的loadData方法加载乱码
 让iis7支持apk文件下载
 sql利用游标循环,遍历表循环结果集
 
 
     
联系作者: QQ: 657603425 Email: [email protected]
Copyright © 2007-2014 www.laozamao.com All Rights Reserved
京ICP备09002242号 北京海淀分局备案号:1101084842