String.replaceAll方法详析(正则妙用)

作者:小姐姐养的狗 时间:2022-02-12 03:07:29 

前言

我通常是不太关心代码的具体实现的,因为我的开发语言很杂,倾向于一些最简单通用的方式去解决。今儿不小心在群里看到一位朋友发了下面的java代码,感觉自己还是很局限很无知的:


String str1 = "createTime";
String str2 = "createTimeAt";
String regex = "([A-Z])+";

System.out.println(str1.replaceAll(regex, "_$1").toLowerCase());
System.out.println(str2.replaceAll(regex, "_$1").toLowerCase());

//result
//create_time
//create_time_at

通过输出可以看到,这段代码的作用是把驼峰命名格式的字符串替换成下划线分割,这个功能比较简单,但是吸引我的却是他的代码。


"createTime".replaceAll("([A-Z]+)","_$1")

这行代码简单的很,就是调用了String类的replaceAll方法,方法的第一个参数是正则表达式,第二个参数是将要被替换成的新值。

让我惊奇的是他代码中,replaceAll的第二个参数,也就是JDK文档中名为replacement的参数,竟然是_$1。这是什么鬼?还支持类似占位符这样的东西?我一直都不知道。

问题探索

由于之前研究过一段正则表达式,通过观察replaceAll的第一个参数([A-Z]+),我猜想,这个应该是用到了正则表达式的分组,对应JDK中,就是java.util.regex.Matcher类的group()方法。

在Linux的Sed命令上,就使用&进行了一些替换,道理应该是相通的。

于是看了下String.replaceAll方法是如何实现的。JDK:


public String replaceAll(String regex, String replacement) {
   return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}

哦,原来它底层就是用了Matcher,只不过用的是Matcher自己的replaceAll方法。

去看它的文档,这个方法的参数果然有鬼,看下面实现代码。


public String replaceAll(String replacement) {
   reset();
   boolean result = find();
   if (result) {
     StringBuilder sb = new StringBuilder();
     do {
       appendReplacement(sb, replacement);
       result = find();
     } while (result);
     appendTail(sb);
     return sb.toString();
   }
   return text.toString();
 }

里面关键的部分就是文档中说的appendReplacement方法,然后可以看到详细的描述文档。

看到这里明白了,原来这个方法的replacement参数可以通过$字符来指代Matcher通过正则匹配得到的分组,支持name和number 两种方式,这里对应的就是Matcher类的group(name)和group(int)两个方法。

结论

1、String的replaceAll方法实际上是通过java.util.regex.Matcher类的replaceAll()方法实现的。

2、java.util.regex.Matcher类的replaceAll方法又是通过调用appendReplacement方法实现替换逻辑

3、Matcher类的appendReplacement方法的replacement参数支持通过$符号来指代Matcher匹配的分组

下面这串代码,就是使用Matcher类分组的一个最佳实践。


String data = "哈哈哈,xjjdog的手机号码是:12345678901,你会打给我吗";
//通过Matcher的分组功能,可以提取出上面字符串中的手机号
Matcher matcher = Pattern.compile(".*(xjjdog的手机号码是:([0-9]{11}))").matcher(data);
while (matcher.find()) {
 System.out.println("G0:" + matcher.group(0));
 System.out.println("G1:" + matcher.group(1));
 System.out.println("G2:" + matcher.group(2));
}
//result
//G0:哈哈哈,xjjdog的手机号码是:12345678901
//G1:xjjdog的手机号码是:12345678901
//G2:12345678901

group(0)表示整个字符串

group(1)表示第一个匹配的,上面的例子中就是(我的手机号码是:([0-9]{11}))部分

group(2)表示第二个匹配的,上面的例子中就是([0-9]{11})部分

使用分组可以用来提取字符串中的目标字符串值,很好用!

几个例子

下面是几个例子,大家可以触类旁通。

驼峰转下划线命名


public static String camelToUnderline(String camelName) {
return camelName.replaceAll("([A-Z]+)", "_$1").toLowerCase();
}

下划线转驼峰

这个稍微麻烦点,是模仿者Matcher.replaceAll方法写的。


public static String underlineToCamel(String underlineName) {
   Matcher matcher = Pattern.compile("(_[a-z]{1})").matcher(underlineName);
   StringBuffer result = new StringBuffer();
   while (matcher.find()) {
     String replacement = matcher.group(1);
     matcher.appendReplacement(result, replacement.replace("_", "").toUpperCase());
   }
   matcher.appendTail(result);
   return result.toString();
}

另外,Mybatis Generator插件源码中的也提供了类似方法(JavaBeansUtil.getCamelCaseString),这里做了下简单修改


public static String getCamelCaseString(String inputString) {
   StringBuilder sb = new StringBuilder();
   boolean nextUpperCase = false;
   for (int i = 0; i < inputString.length(); i++) {
     char c = inputString.charAt(i);
     switch (c) {
       case '_':
       case '-':
       case '@':
       case '$':
       case '#':
       case ' ':
       case '/':
       case '&':
         if (sb.length() > 0) {
           nextUpperCase = true;
         }
         break;
       default:
         if (nextUpperCase) {
           sb.append(Character.toUpperCase(c));
           nextUpperCase = false;
         } else {
           sb.append(Character.toLowerCase(c));
         }
         break;
     }
   }
   return sb.toString();
 }

没有复杂的正则参与,速度显而快了不少。

总结

看一些优秀的开源代码,确实能够了解到一些实用的技巧。这比起自己费劲心力重复制造一些轮子,要高效的多。时间要用在刀刃上,但不是用来切豆腐。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

来源:https://mp.weixin.qq.com/s?__biz=MzA4MTc4NTUxNQ==&mid=2650520031&idx=1&sn=c13f320f7bf80a8e7514de4eb93a9c21

标签:string.replaceall,方法,正则
0
投稿

猜你喜欢

  • Java动态线程池插件dynamic-tp集成zookeeper

    2023-11-25 03:41:38
  • JDK14新特性之switch表达式的实现

    2022-06-01 17:49:31
  • Spring Boot加密配置文件特殊内容的示例代码详解

    2023-09-18 08:47:24
  • SpringBoot 将配置文件挂到 jar 包外面的操作方法

    2023-11-17 11:09:32
  • 面试官:详细谈谈Java对象的4种引用方式

    2022-09-19 04:52:20
  • Jexcel实现按一定规则分割excel文件的方法

    2023-06-29 07:52:01
  • c#读写App.config,ConfigurationManager.AppSettings 不生效的解决方法

    2021-10-07 22:34:42
  • IDEA中设置代码自动提示为Alt+/的具体做法

    2022-07-06 14:58:32
  • IDEA基于支付宝小程序搭建springboot项目的详细步骤

    2021-10-30 22:44:46
  • 英语单词state与status的区别

    2021-09-04 13:57:34
  • spring boot整合log4j2及MQ消费处理系统日志示例

    2023-06-17 17:47:54
  • Java编写实现坦克大战小游戏

    2023-11-24 09:15:34
  • Spring Boot 中application.yml与bootstrap.yml的区别

    2023-07-09 12:30:56
  • Java基于zxing生成二维码矩阵过程解析

    2023-11-23 06:04:06
  • SpringBoot中使用Session共享实现分布式部署的示例代码

    2022-10-17 04:27:54
  • Java实现将每日新闻添加到自己博客中

    2023-02-08 16:20:43
  • 详解Kotlin中的面向对象(一)

    2023-08-17 12:57:38
  • 读取xml文件中的配置参数实例

    2023-10-16 16:20:41
  • Swagger2配置方式(解决404报错)

    2022-08-30 17:21:13
  • mybatis中批量插入的两种方式(高效插入)

    2023-09-16 22:21:07
  • asp之家 软件编程 m.aspxhome.com