正则表达式

读懂正则表达式就这么简单

 

一 前言

  对于正则表达式,相信很多人都知道,但是很多人的第一感觉就是难学,因为看第一眼时,觉得完全没有规律可寻,而且全是一堆各种各样的特殊符号,完全不知所云。

其实只是对正则不了解而以,了解了你就会发现,原来就这样啊正则所用的相关字符其实不多,也不难记,更不难懂,唯一难的就是组合起来之后,可读性比较差,而且不容易理解,本文旨在让大家对正则有一个基本的了解,能看得懂简单的正则表达式,写得出简单的正则表达式,用以满足日常开发中的需求即可。

0/d{2}-/d{8}|0/d{3}-/d{7} 先来一段正则,如果你对正则不了解,是不是完全不知道这一串字符是什么意思?这不要紧文章会详细解释每个字符的含义的。

 

1.1 什么是正则表达式

     正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去匹配符合规则的字符。

1.2 常用的正则匹配工具 

     在线匹配工具:

  1 http://www.regexpal.com/ 

      2 http://rubular.com/ 

     正则匹配软件

      McTracer 

      用过几个之后还是觉得这个是最好用的,支持将正则导成对应的语言如java C# js等还帮你转义了,Copy直接用就行了很方便,另外支持把正则表达式用法解释,如哪一段是捕获分组,哪段是贪婪匹配等等,总之用起来 So Happy .

 

二 正则字符简单介绍

2.1 元字符介绍

   “^” :^会匹配行或者字符串的起始位置,有时还会匹配整个文档的起始位置。 

   “$”  :$会匹配行或字符串的结尾

    如图

         而且被匹配的字符必须是以This开头有空格也不行,必须以Regex结尾,也不能有空格与其它字符

正则表达式     正则表达式

 

 “/b” :不会消耗任何字符只匹配一个位置,常用于匹配单词边界 如 我想从字符串中”This is Regex”匹配单独的单词 “is” 正则就要写成 “/bis/b”  

    /b 不会匹配is 两边的字符,但它会识别is 两边是否为单词的边界 

 “/d”: 匹配数字,

    例如要匹配一个固定格式的电话号码以0开头前4位后7位,如0737-5686123  正则:^0/d/d/d-/d/d/d/d/d/d/d$ 这里只是为了介绍”/d”字符,实际上有更好的写法会在     下面介绍。

 “/w”:匹配字母,数字,下划线.

    例如我要匹配”a2345BCD__TTz” 正则:”/w+”  这里的”+”字符为一个量词指重复的次数,稍后会详细介绍。

 “/s”:匹配空格 

    例如字符 “a b c” 正则:”/w/s/w/s/w”  一个字符后跟一个空格,如有字符间有多个空格直接把”/s” 写成 “/s+” 让空格重复

  “.”:匹配除了换行符以外的任何字符

    这个算是”/w”的加强版了”/w”不能匹配 空格 如果把字符串加上空格用”/w”就受限了,看下用 “.”是如何匹配字符”a23 4 5 B C D__TTz”  正则:”.+”

  “[abc]”: 字符组  匹配包含括号内元素的字符 

        这个比较简单了只匹配括号内存在的字符,还可以写成[a-z]匹配a至z的所以字母就等于可以用来控制只能输入英文了,

 

2.2 几种反义

  写法很简单改成大写就行了,意思与原来的相反,这里就不举例子了

   /W”   匹配任意不是字母,数字,下划线 的字符

   “/S”   匹配任意不是空白符的字符

 ”/D”  匹配任意非数字的字符

   “/B”  匹配不是单词开头或结束的位置

   “[^abc]”  匹配除了abc以外的任意字符

 

 2.3  量词

  先解释关于量词所涉及到的重要的三个概念

    贪婪(贪心) 如”*”字符 贪婪量词会首先匹配整个字符串,尝试匹配时,它会选定尽可能多的内容,如果 失败则回退一个字符,然后再次尝试回退的过程就叫做回溯,它会每次回退一个字符,直到找到匹配的内容或者没有字符可以回退。相比下面两种贪婪量词对资源的消耗是最大的,

   懒惰(勉强) 如 “?”  懒惰量词使用另一种方式匹配,它从目标的起始位置开始尝试匹配,每次检查一个字符,并寻找它要匹配的内容,如此循环直到字符结尾处。

   占有  如”+” 占有量词会覆盖事个目标字符串,然后尝试寻找匹配内容 ,但它只尝试一次,不会回溯,就好比先抓一把石头,然后从石头中挑出黄金

     “*”(贪婪)   重复零次或更多

     例如”aaaaaaaa” 匹配字符串中所有的a  正则: “a*”   会出到所有的字符”a”

     “+”(懒惰)   重复一次或更多次

       例如”aaaaaaaa” 匹配字符串中所有的a  正则: “a+”  会取到字符中所有的a字符,  “a+”与”a*”不同在于”+”至少是一次而”*” 可以是0次,

       稍后会与”?”字符结合来体现这种区别

     “?”(占有)   重复零次或一次

       例如”aaaaaaaa” 匹配字符串中的a 正则 : “a?” 只会匹配一次,也就是结果只是单个字符a

   “{n}”  重复n次

       例如从”aaaaaaaa” 匹配字符串的a 并重复3次 正则:  “a{3}”  结果就是取到3个a字符  “aaa”;

   “{n,m}”  重复n到m次

       例如正则 “a{3,4}” 将a重复匹配3次或者4次 所以供匹配的字符可以是三个”aaa”也可以是四个”aaaa” 正则都可以匹配到

     “{n,}”  重复n次或更多次

       与{n,m}不同之处就在于匹配的次数将没有上限,但至少要重复n次 如 正则”a{3,}” a至少要重复3次

 把量词了解了之后之前匹配电话号码的正则现在就可以改得简单点了^0/d/d/d-/d/d/d/d/d/d/d$ 可以改为”^0/d+-/d{7}$”。

这样写还不够完美如果因为前面的区号没有做限定,以至于可以输入很多们,而通常只能是3位或者4位,

现在再改一下 “^0/d{2,3}-/d{7}”如此一来区号部分就可以匹配3位或者4位的了

 2.4 懒惰限定符

  “*?”   重复任意次,但尽可能少重复 

      如 “acbacb”  正则  “a.*?b” 只会取到第一个”acb” 原本可以全部取到但加了限定符后,只会匹配尽可能少的字符 ,而”acbacb”最少字符的结果就是”acb” 

  “+?”  重复1次或更多次,但尽可能少重复

     与上面一样,只是至少要重复1次

  “??”  重复0次或1次,但尽可能少重复

      如 “aaacb” 正则 “a.??b” 只会取到最后的三个字符”acb”

  “{n,m}?”  重复n到m次,但尽可能少重复

          如 “aaaaaaaa”  正则 “a{0,m}” 因为最少是0次所以取到结果为空

  “{n,}?”    重复n次以上,但尽可能少重复

          如 “aaaaaaa”  正则 “a{1,}” 最少是1次所以取到结果为 “a”

 

三  正则进阶

     3.1 捕获分组

  先了解在正则中捕获分组的概念,其实就是一个括号内的内容 如 “(/d)/d” 而”(/d)” 这就是一个捕获分组,可以对捕获分组进行 后向引用 (如果后而有相同的内容则可以直接引用前面定义的捕获组,以简化表达式) 如(/d)/d/1 这里的”/1″就是对”(/d)”的后向引用

那捕获分组有什么用呢看个例子就知道了

如  “zery zery” 正则 /b(/w+)/b/s/1/b 所以这里的”/1″所捕获到的字符也是 与(/w+)一样的”zery”,为了让组名更有意义,组名是可以自定义名字的

“/b(?<name>/w+)/b/s/k<name>/b” 用”?<name>”就可以自定义组名了而要后向引用组时要记得写成 “/k<name>”;自定义组名后,捕获组中匹配到的值就会保存在定义的组名里

下面列出捕获分组常有的用法

 

“(exp)”    匹配exp,并捕获文本到自动命名的组里

“(?<name>exp)”   匹配exp,并捕获文本到名称为name的组里

“(?:exp)”  匹配exp,不捕获匹配的文本,也不给此分组分配组号

以下为零宽断言

“(?=exp)”  匹配exp前面的位置

  如 “How are you doing” 正则”(?<txt>.+(?=ing))” 这里取ing前所有的字符,并定义了一个捕获分组名字为 “txt” 而”txt”这个组里的值为”How are you do”;

“(?<=exp)”  匹配exp后面的位置

  如 “How are you doing” 正则”(?<txt>(?<=How).+)” 这里取”How”之后所有的字符,并定义了一个捕获分组名字为 “txt” 而”txt”这个组里的值为” are you doing”;

“(?!exp)”  匹配后面跟的不是exp的位置

  如 “123abc” 正则 “/d{3}(?!/d)”匹配3位数字后非数字的结果

“(?<!exp)”  匹配前面不是exp的位置

  如 “abc123 ” 正则 “(?<![0-9])123″ 匹配”123″前面是非数字的结果也可写成”(?!</d)123”

 

四  正则实战

  正则在做验证,与数据过滤时体现的威力是巨大的,我想用过的朋友都知道,下面我们把刚刚了解的全部结合起来做一次实战 做数据采集用正则过滤Html标签并取相应的数据

我们的战场就选在博客园吧,假设现在要采集博客园首页的所有文章信息 包括文章标题,链接接 作者博客地址,文章简介,文章发布时间,阅读数据,评论数 ,推荐数。

 

先看博客园文章的Html格式

正则表达式
<div class="post_item">
<div class="digg">
    <div class="diggit" onclick="DiggIt(3439076,120879,1)"> 
    <span class="diggnum" id="digg_count_3439076">4</span>
    </div>
    <div class="clear"></div>    
    <div id="digg_tip_3439076" class="digg_tip"></div>
</div>      
<div class="post_item_body">
    <h3><a class="titlelnk" href="http://www.cnblogs.com/swq6413/p/3439076.html" target="_blank">分享完整的项目工程目录结构</a></h3>                   
    <p class="post_item_summary">
<a href="http://www.cnblogs.com/swq6413/" target="_blank"><img width="48" height="48" class="pfs" src="http://pic.cnitblog.com/face/142964/20131116170946.png" alt=""/></a>    在项目开发过程中,如何有序的保存项目中的各类数据文件,建立一个分类清晰、方便管理的目录结构是非常重要的。 综合以前的项目和一些朋友的项目结构,我整理了一份我觉得还不错的项目目录结构。 在这里分享给大家,欢迎各位提出你宝贵的意见和建议。如果喜欢请“推荐”则个,感激万分!! 整个目录设置到4级子目录,实... 
    </p>              
    <div class="post_item_foot">                    
    <a href="http://www.cnblogs.com/swq6413/" class="lightblue">七少爷</a> 
    发布于 2013-11-23 15:48 
    <span class="article_comment"><a href="http://www.cnblogs.com/swq6413/p/3439076.html#commentform" title="2013-11-23 16:40" class="gray">
        评论(4)</a></span><span class="article_view"><a href="http://www.cnblogs.com/swq6413/p/3439076.html" class="gray">阅读(206)</a></span></div>
</div>
<div class="clear"></div>
</div>
正则表达式

 

 

 通过构造一个Http请求来取到数据并对数据进行相应处理得到关键信息,在过滤Html标签取文章时正则的强大的威力就体现出来了,

正则的知识点也都基本用上了比如 “/s /w+ . * ? “还有捕获分组,零宽断言等等。喜欢的朋友可以试一试,然后自己看如何通过正则取相应数据的,代码中的正则都是很基本简单的,其意思与用法都在上文中详细写了。

 

正则表达式
    class Program
    {
        static void Main(string[] args)
        {
         
            string content = HttpUtility.HttpGetHtml();
            HttpUtility.GetArticles(content);
        }
    }

    internal class HttpUtility
    {
        //默认获取第一页数据
        public static string HttpGetHtml()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.cnblogs.com/");
            request.Accept = "text/plain, */*; q=0.01";
            request.Method = "GET";
            request.Headers.Add("Accept-Language", "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
            request.ContentLength = 0;
           
            request.Host = "www.cnblogs.com";
            request.UserAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.1 (KHTML, like Gecko) Maxthon/4.1.3.5000 Chrome/26.0.1410.43 Safari/537.1";
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream responStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(responStream, Encoding.UTF8);
            string content = reader.ReadToEnd();
            return content;

        }

        public static List<Article> GetArticles(string htmlString)
        {
            List<Article> articleList = new List<Article>();
            Regex regex = null;
            Article article = null;
            regex = new Regex("<div class=/"post_item/">(?<content>.*?)(?=<div class=/"clear/">" + @"</div>/s*</div>)",
                              RegexOptions.Singleline);

            if (regex.IsMatch(htmlString))
            {
                MatchCollection aritcles = regex.Matches(htmlString);

                foreach (Match item in aritcles)
                {
                    article = new Article();
                    //取推荐
                    regex =
                        new Regex(
                            "<div class=/"digg/">.*<span.*>(?<digNum>.*)" + @"</span>" +
                            ".*<div class=/"post_item_body/">", RegexOptions.Singleline);
                    article.DiggNum = regex.Match(item.Value).Groups["digNum"].Value;

                    //取文章标题 需要去除转义字符
                    regex = new Regex("<h3>(?<a>.*)</h3>", RegexOptions.Singleline);
                    string a = regex.Match(item.Value).Groups["a"].Value;
                    regex = new Regex("<a//s.*href=/"(?<href>.*?)/".*>(?<summary>.*)</a>", RegexOptions.Singleline);
                    article.AritcleUrl = regex.Match(a).Groups["href"].Value;
                    article.AritcleTitle = regex.Match(a).Groups["summary"].Value;

                    //取作者图片 
                    regex = new Regex("<a.*>(?<img><img[^>].*>)</a>", RegexOptions.Singleline);
                    article.AuthorImg = regex.Match(item.Value).Groups["img"].Value;

                    //取作者博客URL及链接的target属性
                    regex = new Regex("<a//s*?href=/"(?<href>.*)/"//s*?target=/"(?<target>.*?)/">.*</a>",
                                      RegexOptions.Singleline);
                    article.AuthorUrl = regex.Match(item.Value).Groups["href"].Value;
                    string urlTarget = regex.Match(item.Value).Groups["target"].Value;

                    //取文章简介
                    //1 先取summary Div中所有内容
                    regex = new Regex("<p class=/"post_item_summary/">(?<summary>.*)</p>", RegexOptions.Singleline);
                    string summary = regex.Match(item.Value).Groups["summary"].Value;
                    //2 取简介
                    regex = new Regex("(?<indroduct>(?<=</a>).*)", RegexOptions.Singleline);
                    article.AritcleInto = regex.Match(summary).Groups["indroduct"].Value;


                    //取发布人与发布时间
                    regex =
                        new Regex(
                            "<div class=/"post_item_foot/">//s*<a.*?>(?<publishName>.*)</a>(?<publishTime>.*)<span class=/"article_comment/">",
                            RegexOptions.Singleline);
                    article.Author = regex.Match(item.Value).Groups["publishName"].Value;
                    article.PublishTime = regex.Match(item.Value).Groups["publishTime"].Value.Trim();

                    //取评论数
                    regex =
                        new Regex(
                            "<span class=/"article_comment/"><a.*>(?<comment>.*)</a></span><span class=/"article_view/">",
                            RegexOptions.Singleline);
                    article.CommentNum = regex.Match(item.Value).Groups["comment"].Value;

                    //取阅读数
                    regex = new Regex("<span//s*class=/"article_view/"><a.*>(?<readNum>.*)</a>", RegexOptions.Singleline);
                    article.ReadNum = regex.Match(item.Value).Groups["readNum"].Value;
                    articleList.Add(article);
                }

            }
            return articleList;
        }



        public static string ClearSpecialTag(string htmlString)
        {

            string htmlStr = Regex.Replace(htmlString, "/n", "", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, "/t", "", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, "/r", "", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, "/"", "'", RegexOptions.IgnoreCase);
            return htmlStr;
        }
    }

    public class Article
    {
        /// <summary>
        /// 文章标题
        /// </summary>
        public string AritcleTitle { get; set; }
        /// <summary>
        /// 文章链接
        /// </summary>
        public string AritcleUrl { get; set; }
        /// <summary>
        /// 文章简介
        /// </summary>
        public string AritcleInto { get; set; }
        /// <summary>
        /// 作者名
        /// </summary>
        public string Author { get; set; }
        /// <summary>
        /// 作者地址
        /// </summary>
        public string AuthorUrl { get; set; }
        /// <summary>
        /// 作者图片
        /// </summary>
        public string AuthorImg { get; set; }
        /// <summary>
        /// 发布时间
        /// </summary>
        public string PublishTime { get; set; }
        /// <summary>
        /// 推荐数
        /// </summary>
        public string DiggNum { get; set; }

        /// <summary>
        /// 评论数
        /// </summary>
        public string CommentNum { get; set; }
        /// <summary>
        /// 阅读数
        /// </summary>
        public string ReadNum { get; set; }

    }
正则表达式

 正则部分可能写得不很完美,但至少也匹配出来了,另外因为自己也是刚接触正则,也只能写出这种比较简单的正则。还望大家海涵~~

 

 

五    总结

  正则其实并不难,了解每个符号的意思后,自己马上动手试一试多写几次自然就明白了,正则是出了名的坑多,随便少写了个点就匹配不到数据了,我也踩了很多坑,踩着踩着就踩出经验了。

本文也只是对正则做了很基本的介绍,还有很多正则的字符没有介绍,只是写了比较常用的一些。如有错误之处,还望在评论中指出,我会马上修改。

 – 此文章转载 – 转载自http://www.cnblogs.com/zery/p/3438845.html

一 前言

  对于正则表达式,相信很多人都知道,但是很多人的第一感觉就是难学,因为看第一眼时,觉得完全没有规律可寻,而且全是一堆各种各样的特殊符号,完全不知所云。

其实只是对正则不了解而以,了解了你就会发现,原来就这样啊正则所用的相关字符其实不多,也不难记,更不难懂,唯一难的就是组合起来之后,可读性比较差,而且不容易理解,本文旨在让大家对正则有一个基本的了解,能看得懂简单的正则表达式,写得出简单的正则表达式,用以满足日常开发中的需求即可。

0/d{2}-/d{8}|0/d{3}-/d{7} 先来一段正则,如果你对正则不了解,是不是完全不知道这一串字符是什么意思?这不要紧文章会详细解释每个字符的含义的。

 

1.1 什么是正则表达式

     正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去匹配符合规则的字符。

1.2 常用的正则匹配工具 

     在线匹配工具:

  1 http://www.regexpal.com/ 

      2 http://rubular.com/ 

     正则匹配软件

      McTracer 

      用过几个之后还是觉得这个是最好用的,支持将正则导成对应的语言如java C# js等还帮你转义了,Copy直接用就行了很方便,另外支持把正则表达式用法解释,如哪一段是捕获分组,哪段是贪婪匹配等等,总之用起来 So Happy .

 

二 正则字符简单介绍

2.1 元字符介绍

   “^” :^会匹配行或者字符串的起始位置,有时还会匹配整个文档的起始位置。 

   “$”  :$会匹配行或字符串的结尾

    如图

         而且被匹配的字符必须是以This开头有空格也不行,必须以Regex结尾,也不能有空格与其它字符

正则表达式     正则表达式

 

 “/b” :不会消耗任何字符只匹配一个位置,常用于匹配单词边界 如 我想从字符串中”This is Regex”匹配单独的单词 “is” 正则就要写成 “/bis/b”  

    /b 不会匹配is 两边的字符,但它会识别is 两边是否为单词的边界 

 “/d”: 匹配数字,

    例如要匹配一个固定格式的电话号码以0开头前4位后7位,如0737-5686123  正则:^0/d/d/d-/d/d/d/d/d/d/d$ 这里只是为了介绍”/d”字符,实际上有更好的写法会在     下面介绍。

 “/w”:匹配字母,数字,下划线.

    例如我要匹配”a2345BCD__TTz” 正则:”/w+”  这里的”+”字符为一个量词指重复的次数,稍后会详细介绍。

 “/s”:匹配空格 

    例如字符 “a b c” 正则:”/w/s/w/s/w”  一个字符后跟一个空格,如有字符间有多个空格直接把”/s” 写成 “/s+” 让空格重复

  “.”:匹配除了换行符以外的任何字符

    这个算是”/w”的加强版了”/w”不能匹配 空格 如果把字符串加上空格用”/w”就受限了,看下用 “.”是如何匹配字符”a23 4 5 B C D__TTz”  正则:”.+”

  “[abc]”: 字符组  匹配包含括号内元素的字符 

        这个比较简单了只匹配括号内存在的字符,还可以写成[a-z]匹配a至z的所以字母就等于可以用来控制只能输入英文了,

 

2.2 几种反义

  写法很简单改成大写就行了,意思与原来的相反,这里就不举例子了

   /W”   匹配任意不是字母,数字,下划线 的字符

   “/S”   匹配任意不是空白符的字符

 ”/D”  匹配任意非数字的字符

   “/B”  匹配不是单词开头或结束的位置

   “[^abc]”  匹配除了abc以外的任意字符

 

 2.3  量词

  先解释关于量词所涉及到的重要的三个概念

    贪婪(贪心) 如”*”字符 贪婪量词会首先匹配整个字符串,尝试匹配时,它会选定尽可能多的内容,如果 失败则回退一个字符,然后再次尝试回退的过程就叫做回溯,它会每次回退一个字符,直到找到匹配的内容或者没有字符可以回退。相比下面两种贪婪量词对资源的消耗是最大的,

   懒惰(勉强) 如 “?”  懒惰量词使用另一种方式匹配,它从目标的起始位置开始尝试匹配,每次检查一个字符,并寻找它要匹配的内容,如此循环直到字符结尾处。

   占有  如”+” 占有量词会覆盖事个目标字符串,然后尝试寻找匹配内容 ,但它只尝试一次,不会回溯,就好比先抓一把石头,然后从石头中挑出黄金

     “*”(贪婪)   重复零次或更多

     例如”aaaaaaaa” 匹配字符串中所有的a  正则: “a*”   会出到所有的字符”a”

     “+”(懒惰)   重复一次或更多次

       例如”aaaaaaaa” 匹配字符串中所有的a  正则: “a+”  会取到字符中所有的a字符,  “a+”与”a*”不同在于”+”至少是一次而”*” 可以是0次,

       稍后会与”?”字符结合来体现这种区别

     “?”(占有)   重复零次或一次

       例如”aaaaaaaa” 匹配字符串中的a 正则 : “a?” 只会匹配一次,也就是结果只是单个字符a

   “{n}”  重复n次

       例如从”aaaaaaaa” 匹配字符串的a 并重复3次 正则:  “a{3}”  结果就是取到3个a字符  “aaa”;

   “{n,m}”  重复n到m次

       例如正则 “a{3,4}” 将a重复匹配3次或者4次 所以供匹配的字符可以是三个”aaa”也可以是四个”aaaa” 正则都可以匹配到

     “{n,}”  重复n次或更多次

       与{n,m}不同之处就在于匹配的次数将没有上限,但至少要重复n次 如 正则”a{3,}” a至少要重复3次

 把量词了解了之后之前匹配电话号码的正则现在就可以改得简单点了^0/d/d/d-/d/d/d/d/d/d/d$ 可以改为”^0/d+-/d{7}$”。

这样写还不够完美如果因为前面的区号没有做限定,以至于可以输入很多们,而通常只能是3位或者4位,

现在再改一下 “^0/d{2,3}-/d{7}”如此一来区号部分就可以匹配3位或者4位的了

 2.4 懒惰限定符

  “*?”   重复任意次,但尽可能少重复 

      如 “acbacb”  正则  “a.*?b” 只会取到第一个”acb” 原本可以全部取到但加了限定符后,只会匹配尽可能少的字符 ,而”acbacb”最少字符的结果就是”acb” 

  “+?”  重复1次或更多次,但尽可能少重复

     与上面一样,只是至少要重复1次

  “??”  重复0次或1次,但尽可能少重复

      如 “aaacb” 正则 “a.??b” 只会取到最后的三个字符”acb”

  “{n,m}?”  重复n到m次,但尽可能少重复

          如 “aaaaaaaa”  正则 “a{0,m}” 因为最少是0次所以取到结果为空

  “{n,}?”    重复n次以上,但尽可能少重复

          如 “aaaaaaa”  正则 “a{1,}” 最少是1次所以取到结果为 “a”

 

三  正则进阶

     3.1 捕获分组

  先了解在正则中捕获分组的概念,其实就是一个括号内的内容 如 “(/d)/d” 而”(/d)” 这就是一个捕获分组,可以对捕获分组进行 后向引用 (如果后而有相同的内容则可以直接引用前面定义的捕获组,以简化表达式) 如(/d)/d/1 这里的”/1″就是对”(/d)”的后向引用

那捕获分组有什么用呢看个例子就知道了

如  “zery zery” 正则 /b(/w+)/b/s/1/b 所以这里的”/1″所捕获到的字符也是 与(/w+)一样的”zery”,为了让组名更有意义,组名是可以自定义名字的

“/b(?<name>/w+)/b/s/k<name>/b” 用”?<name>”就可以自定义组名了而要后向引用组时要记得写成 “/k<name>”;自定义组名后,捕获组中匹配到的值就会保存在定义的组名里

下面列出捕获分组常有的用法

 

“(exp)”    匹配exp,并捕获文本到自动命名的组里

“(?<name>exp)”   匹配exp,并捕获文本到名称为name的组里

“(?:exp)”  匹配exp,不捕获匹配的文本,也不给此分组分配组号

以下为零宽断言

“(?=exp)”  匹配exp前面的位置

  如 “How are you doing” 正则”(?<txt>.+(?=ing))” 这里取ing前所有的字符,并定义了一个捕获分组名字为 “txt” 而”txt”这个组里的值为”How are you do”;

“(?<=exp)”  匹配exp后面的位置

  如 “How are you doing” 正则”(?<txt>(?<=How).+)” 这里取”How”之后所有的字符,并定义了一个捕获分组名字为 “txt” 而”txt”这个组里的值为” are you doing”;

“(?!exp)”  匹配后面跟的不是exp的位置

  如 “123abc” 正则 “/d{3}(?!/d)”匹配3位数字后非数字的结果

“(?<!exp)”  匹配前面不是exp的位置

  如 “abc123 ” 正则 “(?<![0-9])123″ 匹配”123″前面是非数字的结果也可写成”(?!</d)123”

 

四  正则实战

  正则在做验证,与数据过滤时体现的威力是巨大的,我想用过的朋友都知道,下面我们把刚刚了解的全部结合起来做一次实战 做数据采集用正则过滤Html标签并取相应的数据

我们的战场就选在博客园吧,假设现在要采集博客园首页的所有文章信息 包括文章标题,链接接 作者博客地址,文章简介,文章发布时间,阅读数据,评论数 ,推荐数。

 

先看博客园文章的Html格式

正则表达式
<div class="post_item">
<div class="digg">
    <div class="diggit" onclick="DiggIt(3439076,120879,1)"> 
    <span class="diggnum" id="digg_count_3439076">4</span>
    </div>
    <div class="clear"></div>    
    <div id="digg_tip_3439076" class="digg_tip"></div>
</div>      
<div class="post_item_body">
    <h3><a class="titlelnk" href="http://www.cnblogs.com/swq6413/p/3439076.html" target="_blank">分享完整的项目工程目录结构</a></h3>                   
    <p class="post_item_summary">
<a href="http://www.cnblogs.com/swq6413/" target="_blank"><img width="48" height="48" class="pfs" src="http://pic.cnitblog.com/face/142964/20131116170946.png" alt=""/></a>    在项目开发过程中,如何有序的保存项目中的各类数据文件,建立一个分类清晰、方便管理的目录结构是非常重要的。 综合以前的项目和一些朋友的项目结构,我整理了一份我觉得还不错的项目目录结构。 在这里分享给大家,欢迎各位提出你宝贵的意见和建议。如果喜欢请“推荐”则个,感激万分!! 整个目录设置到4级子目录,实... 
    </p>              
    <div class="post_item_foot">                    
    <a href="http://www.cnblogs.com/swq6413/" class="lightblue">七少爷</a> 
    发布于 2013-11-23 15:48 
    <span class="article_comment"><a href="http://www.cnblogs.com/swq6413/p/3439076.html#commentform" title="2013-11-23 16:40" class="gray">
        评论(4)</a></span><span class="article_view"><a href="http://www.cnblogs.com/swq6413/p/3439076.html" class="gray">阅读(206)</a></span></div>
</div>
<div class="clear"></div>
</div>
正则表达式

 

 

 通过构造一个Http请求来取到数据并对数据进行相应处理得到关键信息,在过滤Html标签取文章时正则的强大的威力就体现出来了,

正则的知识点也都基本用上了比如 “/s /w+ . * ? “还有捕获分组,零宽断言等等。喜欢的朋友可以试一试,然后自己看如何通过正则取相应数据的,代码中的正则都是很基本简单的,其意思与用法都在上文中详细写了。

 

正则表达式
    class Program
    {
        static void Main(string[] args)
        {
         
            string content = HttpUtility.HttpGetHtml();
            HttpUtility.GetArticles(content);
        }
    }

    internal class HttpUtility
    {
        //默认获取第一页数据
        public static string HttpGetHtml()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.cnblogs.com/");
            request.Accept = "text/plain, */*; q=0.01";
            request.Method = "GET";
            request.Headers.Add("Accept-Language", "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
            request.ContentLength = 0;
           
            request.Host = "www.cnblogs.com";
            request.UserAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.1 (KHTML, like Gecko) Maxthon/4.1.3.5000 Chrome/26.0.1410.43 Safari/537.1";
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream responStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(responStream, Encoding.UTF8);
            string content = reader.ReadToEnd();
            return content;

        }

        public static List<Article> GetArticles(string htmlString)
        {
            List<Article> articleList = new List<Article>();
            Regex regex = null;
            Article article = null;
            regex = new Regex("<div class=/"post_item/">(?<content>.*?)(?=<div class=/"clear/">" + @"</div>/s*</div>)",
                              RegexOptions.Singleline);

            if (regex.IsMatch(htmlString))
            {
                MatchCollection aritcles = regex.Matches(htmlString);

                foreach (Match item in aritcles)
                {
                    article = new Article();
                    //取推荐
                    regex =
                        new Regex(
                            "<div class=/"digg/">.*<span.*>(?<digNum>.*)" + @"</span>" +
                            ".*<div class=/"post_item_body/">", RegexOptions.Singleline);
                    article.DiggNum = regex.Match(item.Value).Groups["digNum"].Value;

                    //取文章标题 需要去除转义字符
                    regex = new Regex("<h3>(?<a>.*)</h3>", RegexOptions.Singleline);
                    string a = regex.Match(item.Value).Groups["a"].Value;
                    regex = new Regex("<a//s.*href=/"(?<href>.*?)/".*>(?<summary>.*)</a>", RegexOptions.Singleline);
                    article.AritcleUrl = regex.Match(a).Groups["href"].Value;
                    article.AritcleTitle = regex.Match(a).Groups["summary"].Value;

                    //取作者图片 
                    regex = new Regex("<a.*>(?<img><img[^>].*>)</a>", RegexOptions.Singleline);
                    article.AuthorImg = regex.Match(item.Value).Groups["img"].Value;

                    //取作者博客URL及链接的target属性
                    regex = new Regex("<a//s*?href=/"(?<href>.*)/"//s*?target=/"(?<target>.*?)/">.*</a>",
                                      RegexOptions.Singleline);
                    article.AuthorUrl = regex.Match(item.Value).Groups["href"].Value;
                    string urlTarget = regex.Match(item.Value).Groups["target"].Value;

                    //取文章简介
                    //1 先取summary Div中所有内容
                    regex = new Regex("<p class=/"post_item_summary/">(?<summary>.*)</p>", RegexOptions.Singleline);
                    string summary = regex.Match(item.Value).Groups["summary"].Value;
                    //2 取简介
                    regex = new Regex("(?<indroduct>(?<=</a>).*)", RegexOptions.Singleline);
                    article.AritcleInto = regex.Match(summary).Groups["indroduct"].Value;


                    //取发布人与发布时间
                    regex =
                        new Regex(
                            "<div class=/"post_item_foot/">//s*<a.*?>(?<publishName>.*)</a>(?<publishTime>.*)<span class=/"article_comment/">",
                            RegexOptions.Singleline);
                    article.Author = regex.Match(item.Value).Groups["publishName"].Value;
                    article.PublishTime = regex.Match(item.Value).Groups["publishTime"].Value.Trim();

                    //取评论数
                    regex =
                        new Regex(
                            "<span class=/"article_comment/"><a.*>(?<comment>.*)</a></span><span class=/"article_view/">",
                            RegexOptions.Singleline);
                    article.CommentNum = regex.Match(item.Value).Groups["comment"].Value;

                    //取阅读数
                    regex = new Regex("<span//s*class=/"article_view/"><a.*>(?<readNum>.*)</a>", RegexOptions.Singleline);
                    article.ReadNum = regex.Match(item.Value).Groups["readNum"].Value;
                    articleList.Add(article);
                }

            }
            return articleList;
        }



        public static string ClearSpecialTag(string htmlString)
        {

            string htmlStr = Regex.Replace(htmlString, "/n", "", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, "/t", "", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, "/r", "", RegexOptions.IgnoreCase);
            htmlStr = Regex.Replace(htmlStr, "/"", "'", RegexOptions.IgnoreCase);
            return htmlStr;
        }
    }

    public class Article
    {
        /// <summary>
        /// 文章标题
        /// </summary>
        public string AritcleTitle { get; set; }
        /// <summary>
        /// 文章链接
        /// </summary>
        public string AritcleUrl { get; set; }
        /// <summary>
        /// 文章简介
        /// </summary>
        public string AritcleInto { get; set; }
        /// <summary>
        /// 作者名
        /// </summary>
        public string Author { get; set; }
        /// <summary>
        /// 作者地址
        /// </summary>
        public string AuthorUrl { get; set; }
        /// <summary>
        /// 作者图片
        /// </summary>
        public string AuthorImg { get; set; }
        /// <summary>
        /// 发布时间
        /// </summary>
        public string PublishTime { get; set; }
        /// <summary>
        /// 推荐数
        /// </summary>
        public string DiggNum { get; set; }

        /// <summary>
        /// 评论数
        /// </summary>
        public string CommentNum { get; set; }
        /// <summary>
        /// 阅读数
        /// </summary>
        public string ReadNum { get; set; }

    }
正则表达式

 正则部分可能写得不很完美,但至少也匹配出来了,另外因为自己也是刚接触正则,也只能写出这种比较简单的正则。还望大家海涵~~

 

 

五    总结

  正则其实并不难,了解每个符号的意思后,自己马上动手试一试多写几次自然就明白了,正则是出了名的坑多,随便少写了个点就匹配不到数据了,我也踩了很多坑,踩着踩着就踩出经验了。

本文也只是对正则做了很基本的介绍,还有很多正则的字符没有介绍,只是写了比较常用的一些。如有错误之处,还望在评论中指出,我会马上修改。

 – 此文章转载 – 转载自http://www.cnblogs.com/zery/p/3438845.html

如何在小程序中调用本地接口

背景:

随着微信小程序开始公测,我司也拿到了AppID,所以开始了微信小程序的趟坑之旅。

由于现在网上已经有很多的《微信小程序从精通到入门》的教程了,所以就不再重复那些,只是讲一下,在开发的过程中,如何使用本地(开发环境)的接口。

因为小程序的开发文档中写到了,wx.request中的URL只能是一个https请求,本地一般来讲是不会有https的-.-

所以我们使用Charles代理来实现需求。

 

前提:

本人认为你现在已经具备以下几个条件:

0.  具有微信小程序开发的权限

1.  知道自家小程序后台配置的信任域名都是什么-.-

2.  有一台Mac(阿哈哈…无视…截图来自Mac…Windows党请多担待)

 

准备工作:

首先我们需要安装如下两个软件:

0.  安装Charles,当然了,是个破解版的-.- 破解方法请自行百度,不赘述

1.  安装微信web开发者工具

 

操作步骤:

到这一步,本人认为你已经安装好了上边两个软件,并且可以正常运行咯。

0.    首先打开Charles,Help->SSL Proxying->Install Charles Root Certificate 安装证书到本地

如何在小程序中调用本地接口如何在小程序中调用本地接口

1.    在钥匙串访问中搜索 Charles 关键字,找到那个证书,点开后将信任选为始终信任

如何在小程序中调用本地接口

如何在小程序中调用本地接口

 

2.    打开 Tools->Map Remote 添加线上域名于本地(开发环境)服务的映射

如何在小程序中调用本地接口

如何在小程序中调用本地接口

如何在小程序中调用本地接口

3.    打开 Proxy->Proxy Settings

4.    选择Proxies选项卡,默认的HTTP Proxy的值是8888,这个端口号需要记着,后边在微信web开发者工具里边要用到的

如何在小程序中调用本地接口

 

5.    选择Mac OS X选项卡,点击启用如下两个选项

如何在小程序中调用本地接口

6.    打开 Proxy->Mac OS X Proxy 启用本地的代理服务

如何在小程序中调用本地接口

7.    这时,Charles已经完成了本地服务代理线上服务的步骤,接下来就是微信web开发者工具中的一些设置

 

8.    在扫码登录后,点击右上角代理的选项

如何在小程序中调用本地接口

9.    选择手动设置代理,然后填写本地的IP,以及前边在Charles中设置的代理端口号(第5步)

如何在小程序中调用本地接口

 

10.  点击保存后,来到微信小程序的项目中,在wx.request中直接填写线上域名后,保存运行,你就会发现Charles中已经收到了来自你本地的一些请求?

如何在小程序中调用本地接口

 

 

 
转载请署原文地址: https://jiasm.github.io/#/blog/36f116c0-aa64-11e6-a1ed-8fca2e8c7bc3

 

MySQL 性能优化:性能提升 50%,延迟降低 60%

当我进入 Pinterest 时,我的头三个星期是在本部度过的,在那里最新工程把解决生产问题的成果应用到了整个软件栈中。在本部,我们通过构建 Pinterest 来学习 Pinterest 是怎样被构建的,并且,仅仅在几天里就提交代码、做出有意义的贡献也不是不常见。在 Pinterest ,新进来的工程师可以灵活地选择参加哪个组,而且作为在本部工作经历的一部分,编写不同部分的代码可以有助于做出这个选择。本部的人通常会做不同的项目,而我的项目则是深入研究 MySQL 的性能优化。Pinterest, MySQL 和 AWS,我的天!我们的 MySQL 完全运行在 AWS 中。尽管使用了相当高性能的实例类型(配备 SSD RAID-0 阵列),和相当简单的工作负载(很多基于主键或简单范围的单点查询),峰值大约 2000 QPS,我们还是无法达到期望的 IO 性能水平。写 IOPS 一旦超过800,就会导致无法接受的延迟和复制滞后。复制滞后或者从库的读性能不足减慢 ETL 和批处理任务,依靠这些批处理任务的任何小组都会受到负面影响。唯一可行的选项是要么选择一个更大的实例,这样会使我们的开销翻倍、消除我们的效率,或者找办法使现存的系统运行地更好。我从我的同事 Rob Wultsch 那接手了这个项目,他已做出很重要的发现:当在 AWS 的 SSD 上运行时,Linux内核版本非常重要。Ubuntu 12.04 携带的默认 3.2 版本没有减少开销, AWS 推荐的最低 3.8 版本也没有(尽管 3.8 仍比 3.2 快了两倍多)。在一个 i2.2xlarge(双SSD RAID-0 阵列)实例、3.2 内核版本上运行 sysbench 勉强在 16 K 随机写时达到 100 MB/sec。将内核升级至 3.8 会使我们在同样的测试上达到 350 MB/sec,但这比期望值还是差了很多。看到这样一个简单的改变引起这样的提升,为我们揭示了许多新的关于低效和差的配置选项的问题和猜想:我们能否从一个更新的内核上获得更好的性能?我们应该改变 OS 级别的其他设置吗?有没有优化可以在 my.conf 中找到?我们怎样能使 MySQL 运行地更快?在寻找答案中,我设计了 60 个基本不同的 sysbench 文件 IO 测试配置,配合不同的内核、文件系统、挂载选项和 RAID 块大小。一旦从这些实验中选取了最佳配置,我又运行另外 20 个左右的 sysbench OLTP ,使用其他的系统配置。基本的测试方法在所有的测试中是相同的:运行测试一个小时,每隔 1 秒收集数据,然后考虑缓存热身时间去掉开始的 600 秒的数据,最后处理剩下的数据。识别出最优配置后,我们重新构建了我们最大的、最重要的服务器,把这些改变放进了生产环境。从 5000 QPS 到 26000 QPS : 扩展 MySQL 性能,无需扩展硬件让我们看看这些改变对一些基本的 sysbench OLTP 测试的影响,我们在 16 线程、 32 线程和几个不同的配置下衡量 p99 响应时间和吞吐量两个指标来看看效果。这里是每种数字代表的含义:MySQL 性能优化:性能提升 50%,延迟降低 60%MySQL 性能优化:性能提升 50%,延迟降低 60%当我们启用所有的优化后,我们发现在 16 和 32 线程下取得了大概 500% 多的读写吞吐量,同时在读写两个方向上降低了 500 ms 的 p99 延迟。在读方面,我们从大概 4100 – 4600 QPS 达到 22000 – 25000以上,分值取决于并发数。在写方面,我们从大概 1000 QPS 达到 5100 – 6000 QPS。这些是在仅仅通过一些简单改变获得的巨大增长空间和性能提升。当然,所有这些人工基准测试如果不能转换成实际成果,都是没有意义的。下图展示了从客户端和服务端的角度看,我们主要集群上的延迟,时间跨度为从升级前几天到升级后几天。这个过程花了一个星期才完成。MySQL 性能优化:性能提升 50%,延迟降低 60%红线表示客户端感觉到的延迟,绿线表示服务端测到的延迟。从客户端看,p99 延迟从一个波动较大、有时超过 100 ms 的 15 – 35 ms 降至相当平稳的 15 ms、有时会有 80 ms 或更低的异常值。服务端测量的延迟也从波动较大的 5 – 15 ms降至基本平稳的 5 ms,其中每天会有一个由系统维护引起的 18 ms 的尖值。此外,从年初起,我们的高峰吞吐量增加了 50%,所以我们不仅在处理相当大的负载(仍然在我们估计的容量里),同时我们还拥有更好、更可预计的吞吐量。而且,对于每个想睡个安稳觉的人而言的好消息是,与系统性能或通用服务器负载相关的换页事件从三月的 300 降至四月和五月两个月加起来的几个。