String.replaceAll方法詳析(正則妙用)
前言
我通常是不太關(guān)心代碼的具體實(shí)現(xiàn)的,因?yàn)槲业拈_(kāi)發(fā)語(yǔ)言很雜,傾向于一些最簡(jiǎn)單通用的方式去解決。今兒不小心在群里看到一位朋友發(fā)了下面的java代碼,感覺(jué)自己還是很局限很無(wú)知的:
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
通過(guò)輸出可以看到,這段代碼的作用是把駝峰命名格式的字符串替換成下劃線分割,這個(gè)功能比較簡(jiǎn)單,但是吸引我的卻是他的代碼。
"createTime".replaceAll("([A-Z]+)","_$1")
這行代碼簡(jiǎn)單的很,就是調(diào)用了String類(lèi)的replaceAll方法,方法的第一個(gè)參數(shù)是正則表達(dá)式,第二個(gè)參數(shù)是將要被替換成的新值。
讓我驚奇的是他代碼中,replaceAll的第二個(gè)參數(shù),也就是JDK文檔中名為replacement的參數(shù),竟然是_$1。這是什么鬼?還支持類(lèi)似占位符這樣的東西?我一直都不知道。
問(wèn)題探索
由于之前研究過(guò)一段正則表達(dá)式,通過(guò)觀察replaceAll的第一個(gè)參數(shù)([A-Z]+),我猜想,這個(gè)應(yīng)該是用到了正則表達(dá)式的分組,對(duì)應(yīng)JDK中,就是java.util.regex.Matcher類(lèi)的group()方法。
在Linux的Sed命令上,就使用&進(jìn)行了一些替換,道理應(yīng)該是相通的。
于是看了下String.replaceAll方法是如何實(shí)現(xiàn)的。JDK:
public String replaceAll(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceAll(replacement); }
哦,原來(lái)它底層就是用了Matcher,只不過(guò)用的是Matcher自己的replaceAll方法。
去看它的文檔,這個(gè)方法的參數(shù)果然有鬼,看下面實(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(); }
里面關(guān)鍵的部分就是文檔中說(shuō)的appendReplacement方法,然后可以看到詳細(xì)的描述文檔。
看到這里明白了,原來(lái)這個(gè)方法的replacement參數(shù)可以通過(guò)$字符來(lái)指代Matcher通過(guò)正則匹配得到的分組,支持name和number 兩種方式,這里對(duì)應(yīng)的就是Matcher類(lèi)的group(name)和group(int)兩個(gè)方法。
結(jié)論
1、String的replaceAll方法實(shí)際上是通過(guò)java.util.regex.Matcher類(lèi)的replaceAll()方法實(shí)現(xiàn)的。
2、java.util.regex.Matcher類(lèi)的replaceAll方法又是通過(guò)調(diào)用appendReplacement方法實(shí)現(xiàn)替換邏輯
3、Matcher類(lèi)的appendReplacement方法的replacement參數(shù)支持通過(guò)$符號(hào)來(lái)指代Matcher匹配的分組
下面這串代碼,就是使用Matcher類(lèi)分組的一個(gè)最佳實(shí)踐。
String data = "哈哈哈,xjjdog的手機(jī)號(hào)碼是:12345678901,你會(huì)打給我嗎"; //通過(guò)Matcher的分組功能,可以提取出上面字符串中的手機(jī)號(hào) Matcher matcher = Pattern.compile(".*(xjjdog的手機(jī)號(hào)碼是:([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的手機(jī)號(hào)碼是:12345678901 //G1:xjjdog的手機(jī)號(hào)碼是:12345678901 //G2:12345678901
group(0)表示整個(gè)字符串
group(1)表示第一個(gè)匹配的,上面的例子中就是(我的手機(jī)號(hào)碼是:([0-9]{11}))部分
group(2)表示第二個(gè)匹配的,上面的例子中就是([0-9]{11})部分
使用分組可以用來(lái)提取字符串中的目標(biāo)字符串值,很好用!
幾個(gè)例子
下面是幾個(gè)例子,大家可以觸類(lèi)旁通。
駝峰轉(zhuǎn)下劃線命名
public static String camelToUnderline(String camelName) { return camelName.replaceAll("([A-Z]+)", "_$1").toLowerCase(); }
下劃線轉(zhuǎn)駝峰
這個(gè)稍微麻煩點(diǎn),是模仿者M(jìn)atcher.replaceAll方法寫(xiě)的。
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插件源碼中的也提供了類(lèi)似方法(JavaBeansUtil.getCamelCaseString),這里做了下簡(jiǎn)單修改
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(); }
沒(méi)有復(fù)雜的正則參與,速度顯而快了不少。
總結(jié)
看一些優(yōu)秀的開(kāi)源代碼,確實(shí)能夠了解到一些實(shí)用的技巧。這比起自己費(fèi)勁心力重復(fù)制造一些輪子,要高效的多。時(shí)間要用在刀刃上,但不是用來(lái)切豆腐。
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
- javascript中使用replaceAll()函數(shù)實(shí)現(xiàn)字符替換的方法
- Javascript中正則表達(dá)式的全局匹配模式分析
- Javascript中使用exec進(jìn)行正則表達(dá)式全局匹配時(shí)的注意事項(xiàng)
- JavaScript實(shí)現(xiàn)的字符串replaceAll函數(shù)代碼分享
- javascript實(shí)現(xiàn)全局匹配并替換的方法
- java中replaceAll替換圓括號(hào)實(shí)例代碼
- Java中replace與replaceAll的區(qū)別與測(cè)試
- java字符串的替換replace、replaceAll、replaceFirst的區(qū)別說(shuō)明
- Java replaceAll()方法報(bào)錯(cuò)Illegal group reference的解決辦法
- 淺談Java中replace與replaceAll區(qū)別
- Java中replace、replaceAll和replaceFirst函數(shù)的用法小結(jié)
- 淺談java中replace()和replaceAll()的區(qū)別
- jQuery中replaceAll()方法用法實(shí)例
- js使用正則實(shí)現(xiàn)ReplaceAll全部替換的方法
- js字符串替換所有的指定字符或文字(推薦replaceAll方法)
- JS中實(shí)現(xiàn)replaceAll的方法(實(shí)例代碼)
- js replace 與replaceall實(shí)例用法詳解
- Flex 字符串ReplaceAll使用說(shuō)明
- JavaScript中使用replace結(jié)合正則實(shí)現(xiàn)replaceAll的效果
相關(guān)文章
SpringCloud Alibaba Nacos 整合SpringBoot A
這篇文章主要介紹了SpringCloud Alibaba Nacos 整合SpringBoot Admin實(shí)戰(zhàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12java累加和校驗(yàn)實(shí)現(xiàn)方式16進(jìn)制(推薦)
下面小編就為大家?guī)?lái)一篇java累加和校驗(yàn)實(shí)現(xiàn)方式16進(jìn)制(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11MyBatis緩存實(shí)現(xiàn)原理及代碼實(shí)例解析
這篇文章主要介紹了MyBatis緩存實(shí)現(xiàn)原理及代碼實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08SpringBoot高并發(fā)下控制限流的幾種實(shí)現(xiàn)方法
隨著業(yè)務(wù)的發(fā)展,高并發(fā)成為很多系統(tǒng)不得不面對(duì)的問(wèn)題,限流作為一種常用的技術(shù)手段,可以幫助我們有效地控制請(qǐng)求的流量,避免系統(tǒng)因過(guò)載而崩潰,本文將介紹在Spring Boot應(yīng)用中實(shí)現(xiàn)限流的幾種方法,需要的朋友可以參考下2024-06-06Java8 中使用Stream 讓List 轉(zhuǎn) Map使用問(wèn)題小結(jié)
這篇文章主要介紹了Java8 中使用Stream 讓List 轉(zhuǎn) Map使用總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-06-06Mybatis多數(shù)據(jù)源切換實(shí)現(xiàn)代碼
這篇文章主要介紹了Mybatis多數(shù)據(jù)源切換實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10