String.replaceAll方法詳析(正則妙用)
前言
我通常是不太關心代碼的具體實現(xiàn)的,因為我的開發(fā)語言很雜,傾向于一些最簡單通用的方式去解決。今兒不小心在群里看到一位朋友發(fā)了下面的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")
這行代碼簡單的很,就是調(diào)用了String類的replaceAll方法,方法的第一個參數(shù)是正則表達式,第二個參數(shù)是將要被替換成的新值。
讓我驚奇的是他代碼中,replaceAll的第二個參數(shù),也就是JDK文檔中名為replacement的參數(shù),竟然是_$1。這是什么鬼?還支持類似占位符這樣的東西?我一直都不知道。
問題探索
由于之前研究過一段正則表達式,通過觀察replaceAll的第一個參數(shù)([A-Z]+),我猜想,這個應該是用到了正則表達式的分組,對應JDK中,就是java.util.regex.Matcher類的group()方法。
在Linux的Sed命令上,就使用&進行了一些替換,道理應該是相通的。
于是看了下String.replaceAll方法是如何實現(xiàn)的。JDK:
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
哦,原來它底層就是用了Matcher,只不過用的是Matcher自己的replaceAll方法。
去看它的文檔,這個方法的參數(shù)果然有鬼,看下面實現(xiàn)代碼。
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參數(shù)可以通過$字符來指代Matcher通過正則匹配得到的分組,支持name和number 兩種方式,這里對應的就是Matcher類的group(name)和group(int)兩個方法。
結(jié)論
1、String的replaceAll方法實際上是通過java.util.regex.Matcher類的replaceAll()方法實現(xiàn)的。
2、java.util.regex.Matcher類的replaceAll方法又是通過調(diào)用appendReplacement方法實現(xiàn)替換邏輯
3、Matcher類的appendReplacement方法的replacement參數(shù)支持通過$符號來指代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})部分
使用分組可以用來提取字符串中的目標字符串值,很好用!
幾個例子
下面是幾個例子,大家可以觸類旁通。
駝峰轉(zhuǎn)下劃線命名
public static String camelToUnderline(String camelName) {
return camelName.replaceAll("([A-Z]+)", "_$1").toLowerCase();
}
下劃線轉(zhuǎn)駝峰
這個稍微麻煩點,是模仿者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();
}
沒有復雜的正則參與,速度顯而快了不少。
總結(jié)
看一些優(yōu)秀的開源代碼,確實能夠了解到一些實用的技巧。這比起自己費勁心力重復制造一些輪子,要高效的多。時間要用在刀刃上,但不是用來切豆腐。
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。
- javascript中使用replaceAll()函數(shù)實現(xiàn)字符替換的方法
- Javascript中正則表達式的全局匹配模式分析
- Javascript中使用exec進行正則表達式全局匹配時的注意事項
- JavaScript實現(xiàn)的字符串replaceAll函數(shù)代碼分享
- javascript實現(xiàn)全局匹配并替換的方法
- java中replaceAll替換圓括號實例代碼
- Java中replace與replaceAll的區(qū)別與測試
- java字符串的替換replace、replaceAll、replaceFirst的區(qū)別說明
- Java replaceAll()方法報錯Illegal group reference的解決辦法
- 淺談Java中replace與replaceAll區(qū)別
- Java中replace、replaceAll和replaceFirst函數(shù)的用法小結(jié)
- 淺談java中replace()和replaceAll()的區(qū)別
- jQuery中replaceAll()方法用法實例
- js使用正則實現(xiàn)ReplaceAll全部替換的方法
- js字符串替換所有的指定字符或文字(推薦replaceAll方法)
- JS中實現(xiàn)replaceAll的方法(實例代碼)
- js replace 與replaceall實例用法詳解
- Flex 字符串ReplaceAll使用說明
- JavaScript中使用replace結(jié)合正則實現(xiàn)replaceAll的效果
相關文章
Java實戰(zhàn)之OutOfMemoryError異常問題及解決方法
這篇文章主要介紹了Java實戰(zhàn)之OutOfMemoryError異常,主要結(jié)合著深入理解Java虛擬機一書當中整理了本篇內(nèi)容,感興趣的朋友一起看看吧2022-04-04
SpringBoot整合SpringBoot-Admin實現(xiàn)監(jiān)控應用功能
本文主要介紹如何整合Spring Boot Admin,以此監(jiān)控Springboot應用,文中有相關的示例代碼供大家參考,需要的朋友可以參考下2023-05-05
SpringBoot快速整合RabbitMq小案例(使用步驟)
這篇文章主要介紹了SpringBoot快速整合RabbitMq小案例,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06
Mybatis分頁插件PageHelper的配置和簡單使用方法(推薦)
在使用Java Spring開發(fā)的時候,Mybatis算是對數(shù)據(jù)庫操作的利器了。這篇文章主要介紹了Mybatis分頁插件PageHelper的配置和使用方法,需要的朋友可以參考下2017-12-12

