蓝玥 發表於 2022-9-19 09:57:58

正则表达式高级用法之分组的使用教程

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">分组的使用场景</a></li><li><a href="#_label1">分组的使用方法</a></li><li><a href="#_label2">捕获组</a></li><li><a href="#_label3">分组的使用实例</a></li><ul class="second_class_ul"><li><a href="#_lab2_3_0">javascript 获取分组内容</a></li><li><a href="#_lab2_3_1">java 获取分组内容</a></li></ul><li><a href="#_label4">小结</a></li><ul class="second_class_ul"></ul><li><a href="#_label5">补充:正则表达式分组及常见的方法</a></li><ul class="second_class_ul"></ul><li><a href="#_label6">总结</a></li><ul class="second_class_ul"></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>分组的使用场景</h2>
<p>在书写正则表达式时,通常情况下,我们有两种场景会使用到分组。</p>
<p>一是:对一个子表达式进行重复;二是:想要获取到子表达式匹配到的内容。</p>
<ul><li>对子表达式进行重复</li></ul>
<p>如果需要重复单个字符,直接在字符后面加上限定符即可,例如 <code>a+</code> 表示匹配1个或一个以上的a,<code>a?</code>表示匹配0个或1个a。</p>
<p>但是我们如果要对多个字符进行重复的话,就需要用到 <strong>分组</strong> 。</p>
<p>比如:<code>(ab){3}</code> 表示 ab 字符重复3次</p>
<p>正则中常用的限定符如下:</p>
<table><thead><tr><th>表达式</th><th>说明</th></tr></thead><tbody><tr><td>X ?</td><td>X ,一次或一次也没有</td></tr><tr><td>X *</td><td>X ,零次或多次</td></tr><tr><td>X +</td><td>X ,一次或多次</td></tr><tr><td>X { n }</td><td>X ,恰好 n 次</td></tr><tr><td>X { n ,}</td><td>X ,至少 n 次</td></tr><tr><td>X { n , m }</td><td>X ,至少 n 次,但是不超过 m 次</td></tr></tbody></table>
<ul><li>获取到子表达式匹配到的内容</li></ul>
<p>比如表达式: <code>*\d**</code>,它表示a-z的字符重复0到多次,后面紧跟0到多个数字,后面再跟上多个a-z的字符。<br />显然,字符串 <code>abcd324232efg</code> 是满足匹配的串。那么,如果我们只想要获取到匹配串中数字 <code>324232</code> 后面的串 <code>efg</code> 呢?</p>
<p>这时,就可以通过分组的方式来改写正则表达式: <code>*\d*(*)</code>。这样,我们就可以通过获取第 1 个分组匹配到的内容来达到目的。</p>
<p class="maodian"><a name="_label1"></a></p><h2>分组的使用方法</h2>
<p>正则中通过小括号<code>&ldquo;()&rdquo;</code>来指定需要重复的子表达式,然后再加上限定符对这个子表达式进行重复。</p>
<p>例如:(abc)? 表示0个或1个abc 。</p>
<p>一组括号里面的表达式就表示一个分组 。</p>
<p class="maodian"><a name="_label2"></a></p><h2>捕获组</h2>
<p>分组可以分为两种形式,<strong>捕获组</strong>和<strong>非捕获组</strong>。</p>
<p>捕获组和非捕获组的区别就是:捕获组表示的分组会捕获文本(即:匹配字符),而非捕获组表示的分组不会捕获文本。</p>
<p><strong>捕获组可以通过从左到右计算其开括号来编号</strong> 。</p>
<p>例如,在表达式 (A)(B(C)) 中,存在四个这样的组:</p>
<table><thead><tr><th>分组编号</th><th>分组编号对应的子表达式</th></tr></thead><tbody><tr><td><strong>0</strong></td><td>(A)(B(C))</td></tr><tr><td><strong>1</strong></td><td>(A)</td></tr><tr><td><strong>2</strong></td><td>(B(C))</td></tr><tr><td><strong>3</strong></td><td>(C)</td></tr></tbody></table>
<p><strong>注意:第0个分组始终代表整个表达式</strong></p>
<blockquote><p>分组的序号可以通过 Back 引用(反向引用) 在表达式中使用,也可以在匹配操作完成后从匹配器检索出分组匹配到的内容。<br />反向引用的知识将会在后续的文章中进行分析。</p></blockquote>
<p class="maodian"><a name="_label3"></a></p><h2>分组的使用实例</h2>
<p>在一个完整的正则中,如果我们只想获取到某个子表达式匹配到的内容,就可以通过分组来达到目的。</p>
<p>比如:</p>
<p>待匹配串:<code>abcd324232efg</code></p>
<p>想要获取到这个字符串中第二次连续出现的字母子串<code>efg</code></p>
<p>我们可以通过分组的方式书写正则: <code>*\d*(*)</code>。</p>
<p>可以看到,我们通过子表达式<code>(*)</code>来匹配第二次连续出现之母的子串,并且通过<code>()</code>添加了分组,这样,我们就可以通过分组来获取到相应的匹配内容了。</p>
<p>具体的获取方法不同的语言的语法可能会有差异,但是原理是相通的。</p>
<p>下面就来看一下 javascript 和 java 中是如何进行处理的?</p>
<p class="maodian"><a name="_lab2_3_0"></a></p><h3>javascript 获取分组内容</h3>
<div class="jb51code"><pre class="brush:js;">var str = "abcd324232efg";
var reg = new RegExp("(*)(\\d*)(*)");
var arr = str.match(reg);
// 显示匹配到的分组内容
alert(arr + "===" + arr + "===" + arr + "===" + arr);
alert(RegExp.$1 + "-----" + RegExp.$2 + "----" + RegExp.$3);
</pre></div>
<p>上面的例子中,我添加了 3 个分组。</p>
<p>通过 <code>arr</code> 和 <code>RegExp.$n</code> 的方式都能获取到分组匹配内容。</p>
<blockquote><p>在 javascript 中 <code>\d</code> 需要进行转义</p></blockquote>
<p class="maodian"><a name="_lab2_3_1"></a></p><h3>java 获取分组内容</h3>
<div class="jb51code"><pre class="brush:java;">public static void main(String[] args) {
    String str = "abcd324232efg";
    Pattern pattern = Pattern.compile("(*)(\\d*)(*)");
    Matcher matcher = pattern.matcher(str);
    if (matcher.find()) {
      System.out.println(matcher.group());
      System.out.println(matcher.group(0));
      System.out.println(matcher.group(1));
      System.out.println(matcher.group(2));
      System.out.println(matcher.group(3));
    }
}
</pre></div>
<p>在 java 中,通过 <code>Matcher.group(n)</code> 的方式拿到分组匹配内容。</p>
<blockquote><p>在 javascript 中 <code>\d</code> 需要进行转义</p></blockquote>
<p class="maodian"><a name="_label4"></a></p><h2>小结</h2>
<p>分组通常有两种使用场景:一是:对一个子表达式进行重复;二是:想要获取到子表达式匹配到的内容。</p>
<p>分组是通过 <code>()</code> 来表示的,它是通过从左到右计算其开括号来进行编号的。</p>
<p class="maodian"><a name="_label5"></a></p><h2>补充:正则表达式分组及常见的方法</h2>
<div class="jb51code"><pre class="brush:java;">/*
* 正则表达式分组功能:
*                 捕获组可以通过从左到右计算其开括号来编号。例如,在表达式 ((A)(B(C))) 中,存在四个这样的组:        
* split(regex)参数是正则表达式    返回值是一个数组
* replaceAll(regex,replacement)        第一个参数是正则表达式, 第二个参数要替换成的字符串
*/
import java.util.Arrays;
public class RegexApply {
        public static void main(String[] args) {
                // TODO Auto-generated method stub
//                demo1();
//                demo2();
//                demo3();
//                demo4();
//                demo5();
//                demo6();
        }
        private static void demo6() {
                /*
               * \\.""将所有的. 替换为空字符串
               * (.)\\1+        "$1"        将第一组出现的多次都替换 第一组出现的一次$ 代表首字符
               */
                String s = "我..我我...我....爱..爱爱爱....爱爱..学.学学..学学学...学习习..习...习.习.习......习习习习";
                String s2 = s.replaceAll("\\.+", "");
                String s3 = s2.replaceAll("(.)\\1+", "$1");       
                System.out.println(s3);
        }
        private static void demo5() {
                /*
               * 叠词切割: "acyyfgttthjzzzzzko";
               * (.)\\1+        //1+代表第一组出现一次到多次
               */
                String s = "acyyfgttthjzzzzzko";
                String regex = "(.)\\1+";                                        //1+代表第一组出现一次到多次
                String[] arr = s.split(regex);
               
                for (int i = 0; i &lt; arr.length; i++) {
                        System.out.println(arr);
                }
        }
        private static void demo4() {
                /*
               * 叠词 捕获组 (.)\\1(.)\\2   \\1代表第一组又出现一次        \\2代表第二组又出现一次
               * (..)\\1                                          \\1代表第一组又出现了一次
               */
                //叠词飘飘亮亮,美美丽丽
                String regex2 = "(.)\\1(.)\\2";                                        //\\1代表第一组又出现一次        \\2代表第二组又出现一次
                System.out.println("漂漂亮亮".matches(regex2));        //true
                System.out.println("美美丽丽".matches(regex2));        //false
                System.out.println("高高兴兴".matches(regex2));        //true
                System.out.println("死啦死啦".matches(regex2));        //false
                System.out.println("----------------------");
                //叠词 漂亮漂亮,美丽美丽
                String regex = "(..)\\1";
                System.out.println("死啦死啦".matches(regex));                //true                       
                System.out.println("高兴高兴".matches(regex));                //true
                System.out.println("快快乐乐".matches(regex));                //false
        }
        private static void demo3() {
                /*
               * replaceAll(regex,replacement)        第一个参数是正则表达式, 第二个参数要替换成的字符串
               */
                String s = "aaoo1ddd3jgjao";
                String regex = "\\d";
                String s2 = s.replaceFirst(regex, "");
                String s3 = s.replaceAll(regex, "");
                System.out.println(s2);                                        //aaooddd3jgjao
                System.out.println(s3);                                        //aaoodddjgjao
        }
        private static void demo2() {
                /*
               * split(regex)参数是正则表达式    返回值是一个数组
               */
                String s = "星期一.星期二.星期三.星期四";
                String[] array = s.split("\\.");
                System.out.println(Arrays.toString(array));
        }
        private static void demo1() {
                /*
               * 校验电话号码
               * 1.必须是5-15位数字
               * 2.开头不能位0
               * 3.必须是纯数字
               */
                String regex = "\\d{5,15}";
                System.out.println("804360385".matches(regex));                                //true
                System.out.println("430763075439703307503".matches(regex));        //false
                System.out.println("03534534".matches(regex));                                //false
        }
}
</pre></div>
<p class="maodian"><a name="_label6"></a></p><h2>总结</h2>
頁: [1]
查看完整版本: 正则表达式高级用法之分组的使用教程