zoukankan      html  css  js  c++  java
  • 正则表达式 之领宽断言

    小括号的作用

    分类     代码/语法     说明

    捕获    
          (exp)        匹配exp,并捕获文本到自动命名的组里
          (?<name>exp)   匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)
          (?:exp)        匹配exp,不捕获匹配的文本,也不给此分组分配组号
    零宽断言
          (?=exp)      匹配exp前面的位置
          (?<=exp)      匹配exp后面的位置
          (?!exp)       匹配后面跟的不是exp的位置
          (?<!exp)     匹配前面不是exp的位置
    注释
          (?#comment) 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读

    要特别注意的是,零宽断言是不占用位置的,也就是说,匹配结果里是不会返回它的。

     (?:exp) 既不捕获匹配的文本,也不给此分组分配组号,这个东西到底有什么用呢?

     (?:exp) 非捕获组,匹配exp的内容,但不捕获到组里

    至于作用,一般来说是为了节省资源,提高效率
    比如说验证输入是否为整数,可以这样写
    ^([1-9][0-9]*|0)$
    这时候我们需要用到()来限制“|”表示“或”关系的范围,但我们只是要判断规则,没必要把exp匹配的内容保存到组里,这时就可以用非捕获组了
    ^(?:[1-9][0-9]*|0)$

      有的时候我们不得不用(),而()默认情况下会将其中exp匹配的内容捕获到组里,而有些情况我们只是判断规则,或者后面并不需要对此处()中匹配的内容进行引用时,就没有必要把它捕获到组里了,一方面会造成资源的浪费,另一方面会降低效率,这时候就要用到非捕获组了。

    至于这些东西,说是说不明白的,看符号也没用,最好就是上例子。

    复制代码
    //正则表达式牛逼,名词好牛B,其实好简单
            static void Main(string[] args)
            {
                //(exp) 匹配exp,并捕获文本到自动命名的组里
                Regex reg = new Regex(@"A(w+)A");
                Console.WriteLine(reg.Match("dsA123A"));    //输出 A123A
                Console.WriteLine(reg.Match("dsA123A").Groups[1]);      //输出123
    
                //(?<name>exp)    匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)
                Regex reg2 = new Regex(@"A(?<num>w+)A");
                Console.WriteLine(reg2.Match("dsA123A").Groups["num"]); //输出123
    
                Regex reg3 = new Regex(@"A(?:w+A)");
                Console.WriteLine(reg3.Match("dsA123A"));
    
                Console.WriteLine("==============================");
    
                //(?=exp)    匹配exp前面的位置  零宽正预测先行断言
                Regex reg4 = new Regex(@"sing(?=ing)");     //表达式的意思是,我认为在sing的后面会有ing,如果sing后面紧跟着ing,那么这个sing才匹配成功,注意断言词不会被匹配
                Console.WriteLine(reg4.Match("ksingkksingingkkk"));     //输出    sing
                Console.WriteLine(reg4.Match("singddddsingingd").Index);   //输出 8   输出8就意味住前面那个sing被没有被匹配
    
                //(?<=exp) 匹配exp后面的位置  零宽度正回顾后发断言
                Regex reg5 = new Regex(@"(?<=wo)man");
                Console.WriteLine(reg5.Match("Hi man Hi woman"));   //输出 man
                Console.WriteLine(reg5.Match("Hi man Hi woman").Index);     //输出 12    掰着手指头算算到底匹配的是哪一个
    
                //(?!exp)    匹配后面跟的不是exp的位置 零宽度负预测先行断言
                Regex reg6 = new Regex(@"sing(?!ing)");
                Console.WriteLine(reg6.Match("singing-singabc"));   //输出 sing
                Console.WriteLine(reg6.Match("singing-singabc").Index); //输出 8  还得掰着手指头算算匹配的是哪一个
    
                //(?<!exp)    匹配前面不是exp的位置 零宽度负回顾后发断言
                Regex reg7 = new Regex(@"(?<!wo)man");
                Console.WriteLine(reg7.Match("Hi woman Hi man"));   //输出 man
                Console.WriteLine(reg7.Match("Hi woman Hi man").Index); //输出 12  算算匹配的是哪一个
    
                //(?#comment)    不对正则表达式的处理产生任何影响,用于提供注释让人阅读
                Regex reg8 = new Regex("ABC(?#这只是一段注释而已)DEF");
                Console.WriteLine(reg8.Match("ABCDEFG"));   //输出 ABCDEF
            }
    复制代码

    懒惰匹配

    代码/语法       说明
    *?          重复任意次,但尽可能少重复
    +?          重复1次或更多次,但尽可能少重复
    ??           重复0次或1次,但尽可能少重复
    {n,m}?         重复n到m次,但尽可能少重复
    {n,}?          重复n次以上,但尽可能少重复

    如果你细心的留意到,会发现,其实懒惰匹配符只是在原有限定符后面加了个?以表示尽可能少地匹配的意思。

    复制代码
    class Program
        {
            //正则表达式牛逼,名词好牛B,其实好简单
            static void Main(string[] args)
            {
                //懒惰匹配
                Regex reg1 = new Regex(@"A(w)*B");
                Console.WriteLine(reg1.Match("A12B34B56B"));    //输出 A12B34B56B //留意到默认是尽可能多地匹配
    
                Regex reg2 = new Regex(@"A(w)*?B"); //w重复任意次,但尽可能少          
                Console.WriteLine(reg2.Match("A12B34B56B"));   //输出 A12B
    
                Regex reg3 = new Regex(@"A(w)+?");  //w重复1次或更多次,但尽可能少
                Console.WriteLine(reg3.Match("AB12B34B56B"));        //输出AB 注意此处测试字符串
    
                Regex reg4 = new Regex(@"A(w)??B");  //w重复0次或1次,但尽可能少
                Console.WriteLine(reg4.Match("A12B34B56B"));    //输出 空白,匹配失败,因为至少也要重复w两次
                Console.WriteLine(reg4.Match("A1B2B34B56B"));   //输出 A1B
    
                Regex reg5 = new Regex(@"A(w){4,10}?B");       //w至少重复4次,最多重复10次
                Console.WriteLine(reg5.Match("A1B2B3B4B5B"));   //输出 A1B2B3B    到了第4个的时候,恰好第4个字符是3只有匹配3后面的那个B了
    
                Regex reg6 = new Regex(@"A(w){4,}?");  //w至少重复4次,最多无上限
                Console.WriteLine(reg5.Match("A1B2B3B4B5B"));   //输出 A1B2B3B    到了第4个的时候,恰好第4个字符是3只有匹配3后面的那个B了
    
                Console.ReadKey();
            }
        }
    复制代码

     平衡组

    正则表达式平衡组用于匹配左右两边开始,结束符号相等数量的内容
      例如,对于字符串"xx <aa <bbb> <bbb> aa> yy>" 左右两边的< > 是不等的,如果简单的<.+>匹配到的是最外层的开始括号<与结束括号 
    >之间的内容,但是开始和封闭的括号数量不一致。如果你希望匹配到的是左右括号正常结束的字符串,那么就需要用到平衡组了。

    平衡组语法:
      (?'group') 把捕获的内容命名为group,并压入堆栈(Stack)
      (?'-group') 从堆栈上弹出最后压入堆栈的名为group的捕获内容,如果堆栈本来为空,则本分组的匹配失败
      (?(group)yes|no) 如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分
      (?!) 零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败

    复制代码
            static void Main(string[] args)
            {
                //平衡组 我们现在要匹配最外层的括号的内容
                string strTag = "xx <aa <bbb> <bbb> aa> yy>";   //要匹配的目标是 <aa <bbb> <bbb> aa>  ,注意括号数不等
                Regex reg = new Regex("<.+>");
                Console.WriteLine(reg.Match(strTag));   //输出 <aa <bbb> <bbb> aa> yy>    看到与希望匹配的目标不一致,主要是因为 < 与 > 的数量不相等
    
                Regex reg3 = new Regex("<[^<>]*(((?'Open'<)[^<>]*)+((?'-Open'>)[^<>]+))*(?(Open)(?!))>");
                Console.WriteLine(reg3.Match(strTag));  //<aa <bbb> <bbb> aa>   目标正确
    
    
                //平衡组最常用的例子,匹配HTML,以下是匹配嵌套DIV里面的内容
                Regex reg2 = new Regex(@"<div[^>]*>[^<>]*(((?'Open'<div[^>]*>)[^<>]*)+((?'-Open'</div>)[^<>]*)+)*(?(Open)(?!))</div>");
                string str = "<a href='http://www.baidu.com'></a><div id='div1'><div id='div2'>你在他乡还好吗?</div></div><p></p>";
                Console.WriteLine(reg2.Match(str));  //输出 <div id='div1'><div id='div2'>你在他乡还好吗?</div></div>
                Console.ReadKey();
            }
    复制代码
    语法解释:
    < #最外层的左括号 [^<>]* #最外层的左括号后面的不是括号的内容 ( ( (?'Open'<) #碰到了左括号,在黑板上写一个"Open" [^<>]* #匹配左括号后面的不是括号的内容 )+ ( (?'-Open'>) #碰到了右括号,擦掉一个"Open" [^<>]* #匹配右括号后面不是括号的内容 )+ )* (?(Open)(?!)) #在遇到最外层的右括号前面,判断黑板上还有没有没擦掉的"Open";如果还有,则匹配失败 > #最外层的右括号
  • 相关阅读:
    VisualSVN-Server windows 版安装时报错 "Service 'VisualSVN Server' failed to start. Please check VisualSVN Server log in Event Viewer for more details."
    Pytest 单元测试框架之初始化和清除环境
    Pytest 单元测试框架入门
    Python(email 邮件收发)
    Python(minidom 模块)
    Python(csv 模块)
    禅道简介
    2020年最好的WooCommerce主题
    Shopify网上开店教程(2020版)
    WooCommerce VS Magento 2020:哪个跨境电商自建站软件更好?
  • 原文地址:https://www.cnblogs.com/zhoading/p/8036441.html
Copyright © 2011-2022 走看看