正则表达式对比(Java和JavaScript)

2023-04-24 15:46:52

正则是一套标准,各个语言都一样,只是各个语言的实现不太一样,下面就主要比较Java和JavaScript的正则

  1. 创建正则–简单使用

    <script>
        //正则字面量 //包裹
        console.log(/20\d\d/.test("2019"))//true
        console.log(/20\d\d/.test("2100"))//false
        let a = "r"
        console.log(/a/.test("345a"))//true
     console.log(eval(`/${a}/`).test("345a"))//false
        let content = "baidu.com"
        let reg = new RegExp("u")//使用对象的形式就不用//包裹了
        console.log(reg.test(content))//true
    </script>
    
    public static void main(String[] args) {
        //因为正则表达式可以用字符串来描述规则,所以都可以使用变量
        String variable = "\\d";
        String regex = "20\\d"+variable;//这相当于正则字面量的形式
        System.out.println("2019".matches(regex));//true
        System.out.println("2100".matches(regex));//false
        boolean matches = Pattern.matches(regex, "2019");//这就是String类matches的源码
        System.out.println(matches);
        Pattern pattern = Pattern.compile("20\\d\\d");//这相当于正则对象
        Matcher matcher = pattern.matcher("2019");
        while (matcher.find()){
            System.out.println(matcher.group());//2019
        }
    }
    
  2. 选择符|

    <script>
        let tel = "010-9999999"//true
        tel = "020-9999999"//true
        tel = "010"//true
        tel = "020"//false
        //,这样表示是否包含010或者020\-\d{7,8}整体匹配到的
    	//其实真实的意思是/[010|020]\-\d{7,8}/
        console.log(/010|020\-\d{7,8}/.test(tel))//test是检测字符串是否包含正则匹配到的内容,只要包含就返回true
    </script>
    
    public static void main(String[] args) {
        String content = "010-9999999";//false
        content = "020-9999999";//true
        content = "020-9999";//false
        content = "010";//true
        content = "020";//false
        System.out.println(content.matches("010|020-\\d{7,8}"));
        //这样写的意思是010或者020-\d{7,8}
        //即选择符右边的是一组,并且matches是整体匹配
        //真实的意思是"[010-020]-\\d{7,8}"
    }
    
  3. 转义-关于转义的理解,js和Java是一样的

    <script>
        //js中\是转义字符:作用是转义后面一个字符(只转义后面第一个字符),正则中\也是转义字符,由于字面量正则/是特殊字符,所以字面量要匹配/也需要转义\/
        console.log("d"==="d")//true
        console.log("\d" === "d")//true 因为d没有特殊含义d转义后还是d
        // console.log("\")//这样写会报错的-- "\"表示一个"和一个普通的"
        console.log("\\")// \
        console.log("\d+\.\d+")//d+.d+
        console.log("\\d+\\.\\d+")//\d+\.\d+
        console.log("\\\\")// \\
        console.log("\\r\\")// \r\
    </script
    
    /**
     * 转义理解
     * Java中\是转义字符,作用是转义后面一个字符(只转义后面第一个字符),把它当作普通字符
     * ”“包裹起来表示字符串 "\"表示一个"和一个普通的",所以这样写是会报错的
     * \\\\ 会输出\\ 可以这样理解 第一个\把第二个\转义了,两个最终输出一个普通的\ 第3个\把第四个\转义了,最终输出一个普通的\ 整体最后输出两个普通的\\
     * \\r\\ 第一个\把第二个\转义 第3个\把第4个\转义 最终输出字符串 \r\
     *
     * 正则当中\也是转义字符 作用后边的一个字符,整体变得特殊 例如 d在正则里就是普通的d \d在正则里就代表数字
     * 所以正则匹配时要写\\d 因为\\d最终代表\d,在正则里才代表数字
     */
    public class RegTransfer {
        public static void main(String[] args) {
            System.out.println("\\");// \
            System.out.println("\\\\");// \\
            System.out.println("\\r\\");// \r\
            System.out.println("234".matches("\\d"));
        }
    }
    
  4. 修饰符

    1. i和g大小写

      <script>
          let content = "123sd#&^%SD"
          let regStr = /[a-z]/ //默认是区分大小写的和非贪婪匹配的 得到的结果 s
          regStr = /[a-z]+/g//得到的结果sd
          regStr = /[a-z]+/ig//得到的结果sd SD
          let match = content.match(regStr);
          console.log(...match)
      </script>
      
      public static void main(String[] args) {
          //大小写
          String content = "123sd#&^%SD";
          String regStr = "(?i)[a-z]+";//(?i)代表后边的忽略大小写不会计入分组 这种方式可以灵活的控制大小写
          regStr = "[a-z]+";
          Pattern pattern = Pattern.compile(regStr);
          pattern = Pattern.compile(regStr, Pattern.CASE_INSENSITIVE);//这样代表整体忽略大小写
          Matcher matcher = pattern.matcher(content);
          while (matcher.find()) {//如果只想取匹配到的第一个这里用if就行了
              System.out.println("找到了:"+matcher.group());
          }
      }
      
    2. 多行操作符

      <script>
         //多行匹配
          let str = `
                  #1 js,90 #
                  #2 java,86 #
                  #3 djfi,3 # dsf
                  #4 Kotlin,87 #
          `
          let reg = /^\s*#\d+.+\s+#$/gm  //m的意思是每行单独对待
         let lessons =  str.match(reg).map(v => {
              v = v.replace(/\s*#\d+\s*/,"").replace(/\s+#/,"");
              [name,price] = v.split(",")
              return {name,price}
          })
          console.log(JSON.stringify(lessons))//[{"name":"js","price":"90"},{"name":"java","price":"86"},{"name":"Kotlin","price":"87"}]
          //
      </script>
      
      fun main() {
          val str =
              """     #1 js,90 #
                  #2 java,86 #
                  #3 djfi,93 # dsf 
                  #4 Kotlin,87 #
          """
          val regStr = "^\\s*#\\d+.+\\s+#$";
          val pattern = Pattern.compile(regStr, Pattern.MULTILINE)
          val matcher = pattern.matcher(str)
          val list = mutableListOf<String>()
          while (matcher.find()) {
              list.add(matcher.group())
          }
          val result = list.map { v ->
             val (name,price) =  v.replace("\\s*#\\d+\\s*".toRegex(), "").replace("\\s+#".toRegex(),"").split(",")
             mapOf("name" to name,"price" to price)
          }
          println(result)//[{name=js, price=90}, {name=java, price=86}, {name=Kotlin, price=87}]
      }
      
      
      public static void main(String[] args) {
         //多行匹配
         String content =
                  "            #1 js,90 #\n" +
                          "            #2 java,86 #\n" +
                          "            #3 djfi,93 # dsf \n" +
                          "            #4 Kotlin,87 #\n" +
                          "    ";
         String regStr = "^\\s*#\\d+.+\\s+#$";
         Pattern pattern = Pattern.compile(regStr, Pattern.MULTILINE);//如果不用MULTILINE模式是不行的
         Matcher matcher = pattern.matcher(content);
          List<String> list = new ArrayList<>();
          while (matcher.find()) {
              list.add(matcher.group());
          }
        List<Map<String,String>> result =  list.stream().map(s -> {
              String[] array = s.replaceAll("\\s*#\\d+", "").replaceAll("\\s#", "").split(",");
              HashMap<String,String> map =new HashMap<>();
              map.put("name", array[0]);
              map.put("price", array[1]);
              return map;
          }).collect(Collectors.toList());
          for (Map<String, String> map : result) {
              System.out.println(map.entrySet());
          }
      }
      
  5. 分组()括住的代表一组以及原子组引用和原子组非捕获

    public static void main(String[] args) {
    //()括起来的是第一组,从左边第一个(括号算是第一组,第二个(是第二组,后面用\1和\2用来引用分组的内容
    //        String content = "df的话覅的1991返回发1234覆盖3333erd12321-333999111";
    //        String regStr = "(\\d)(\\d)\\2\\1";//连续4位数,第1位和第四位相同,第二位和第三位相同
    //        String regStr = "(\\d)\\1{3}";//连续4位数,都相同
            String regStr = "\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";//前面是一个5位数,然后是一个-号,然后是一个9位数,连续的每3位相同
    
            String content = "我....我要....学学学学....编程Java!";//结巴语句变成我哟啊学编程Java
            content = content.replaceAll("\\.", "").replaceAll("(.)\\1+","$1");
    //        String $1 = Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1");//$1是在外部使用反向引用
    //        System.out.println($1);
            System.out.println(content);//我要学编程java
    
            Pattern pattern = Pattern.compile(regStr);
            Matcher matcher = pattern.matcher(content);
            while (matcher.find()) {
                System.out.println("找到了:"+matcher.group(0));
            }
        
        //----------------------------------- 非捕获分组和js差不多
                String str = "parade岁月山大佛i和房符合parade0393df发parade同学";
            String regEStr = "parade(?:岁月|0393)";//不会捕获分组
    //        String regEStr = "parade(?:岁月|0393|同学)";//parade岁月和parade0393和parade同学 不会捕获分组
    //        String regEStr = "parade(岁月|0393)";//parade岁月和parade0393 会捕获分组
    //        String regEStr = "parade(?=岁月|0393)";//parade和parade 非捕获parade岁月的parade和parade0393的parade
    //        String regEStr = "parade(?!岁月|0393)";//parade和parade 非捕获parade岁月的parade和parade0393的parade
            Pattern compile = Pattern.compile(regEStr);//parade后边不是岁月和0393的parade  和上面的是取反
            Matcher match = compile.matcher(str);
            while (match.find()) {
                System.out.println(match.group(0));
    //            System.out.println(match.group(1));//使用非捕获分组,这里写就会报错IndexOutOfBoundsException
            }
        //其他的非捕获分组?<= ?<! 这些非捕获分组只是条件 准确的来说叫断言 修饰符是不能修饰这些断言的
        }
    
    <script>
        let content = "df的话覅的1991返回发1234覆盖3333erd12321-333999111"
        let reg = /(\d)(\d)\2\1/g//连续四位数,第一位和第4位相同,第2位和第3位相同 --1991和3333
        reg = /(\d)\1{3}/g//连续4位数都相同--3333
        reg = /\d{5}-(\d)\1{2}(\d)\2{2}(\d)\3{2}/g//前面是一个5位数,然后是一个-号,然后是一个9位数,连续的每3位相同--12321-333999111
        content = "我....我要....学学学学....编程Java!"//我要学编程Java
        reg = /\./g
       content = content.replace(reg,"").replace(/(.)\1+/g,"$1")
        console.log(content)//我要学编程Java
        // console.log(content.match(reg))//
        content = "parade岁月山大佛i和房符合parade0393df发parade同学";
        //reg = /parade(?<alias>岁月|0393)/g//会捕获分组 res[1]输出岁月和0393 ?<name>代表给分组起别名
        // reg = /parade(?:岁月|0393)/g//不会捕获分组 res[1]输出undefined 这里需要使用g修饰符,否则只会匹配一个
    	// reg = /parade(?=0393|岁月)/g//不会捕获分组
    	reg = /parade(?!0393|岁月)/g//不会捕获分组 parade同学的parade
        let result = []
        while ((res = reg.exec(content))){
            result.push(res)
            // console.log(res[1])//代表第一个分组,使用?:
            // console.log(res.groups.alias)//和res[1]效果是一样的 alias是给分组起的别名
        }
        console.log(result)
    </script>
    
  6. 贪婪匹配

    /**
     * java默认是贪婪匹配的
     * 任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的后边紧跟是非贪婪的
     * 非贪婪匹配是尽可能少的匹配
     */
    public static void main(String[] args) {
            String content = "123000";
            String regStr = "(\\d+?)(0*)";//如果"(\\d+)(0*)",那么第一组是123000,第二组是""空字符串
            content = "hello234okdfsdf34ok";
            regStr = "\\d+?ok";//此时"\\d+?ok"效果一样
            regStr = "\\d+";//此时匹配 234和34
            regStr = "\\d+?";//此时匹配 2 3 4 3 4
            Pattern pattern = Pattern.compile(regStr);
            Matcher matcher = pattern.matcher(content);
    //        if (matcher.matches()) {//matches是整体匹配
    //            System.out.println("整体找到:"+matcher.group());
    //            System.out.println("group1:"+matcher.group(1));
    //            System.out.println("group2:"+matcher.group(2));
    //        }
            StringBuffer buffer = new StringBuffer();
            while (matcher.find()) {
                matcher.appendReplacement(buffer, "-");
                System.out.println("找到了:" + matcher.group());
            }
            matcher.appendTail(buffer);//如果没有这一句下面会输出hello---okdfsdf--,有这一句会输出hello---okdfsdf--ok
            System.out.println(buffer);
        }
    
    <script>
        let content = "123000"
        let reg = /^(\d+)(0*)$///默认也是贪婪的
        console.log(content.match(reg))//第一组是123000
        reg = /^(\d+?)(0*)$///禁止贪婪
        console.log(content.match(reg))//第一组是123 match默认不是整体匹配
    </script>
    
  7. 方法使用对比

    /**
     * String类的方法
     * 1.split(String regex) 注意如果开头就匹配,那最终数组第一个元素是空字符
     * 2.replaceAll(String regx)
     * 3.replaceFirst(String regx)
     * 4.matches(String regx)//注意此方法是整体匹配  部分匹配请使用Matcher 类的find方法
     * Matcher类的方法
     * 1.find
     * 2.matches 和String类的matches效果一样
     * 3.lookAt() 从头开始找 非整体,找不到就返回false即有子字符串符合
     * 4.replaceAll 和replaceFirst和String类的效果一样
     * 5.appendReplacement 和 appendTail 结合 find可以在循环查找的时候定义每个匹配到的字符串的替换规则
     */
    public class RegSummary {
        public static void main(String[] args) {
            String content = "1parade岁月山大佛i和房符合parade0393df发parade同学";
            String regStr = "parade(0393|岁月)";
            String[] split = content.split(regStr);
            //注意如果开头就匹配,那最终数组第一个元素是空字符
    //        System.out.println(split.length);//3
            for (String s : split) {
    //            System.out.println(s);//山大佛i和房符合  和  df发parade同学 其实数组有3个元素,第一个是空字符
            }
            //如果limit参数为 0 或 负数,则split()返回包含所有子字符串的数组。
            //如果limit参数为正(例如n),则split()返回数组的最大长度。
            String
    
    
    
    
    
    							
  • 作者:parade岁月
  • 原文链接:https://blog.csdn.net/parade0393/article/details/124087201
    更新时间:2023-04-24 15:46:52