replace、replaceAll、replaceFirst这三个函数会java的同学估计都用过,笔者已经用了2年多,可是,我们真的懂他们吗?

概述一下他们三个的用法:

· replace(CharSequence target, CharSequence replacement),用replacement替换所有的target,两个参数都是字符串。

· replaceAll(String regex, String replacement),用replacement替换所有的regex匹配项,regex很明显是个正则表达式,replacement是字符串。

· replaceFirst(String regex, String replacement),基本和replaceAll相同,区别是只替换第一个匹配项。

接下来有个简单的需求,就是把源字符串中的a替换成\a,代码如下:

1 System.out.println("abac".replace("a", "\\a")); //\ab\ac
2 System.out.println("abac".replaceAll("a", "\\a")); //abac
3 System.out.println("abac".replaceFirst("a", "\\a")); //abac

结果让人大吃一惊,用了这么多年的替换,竟然有点蒙了。

源字符串是"abac",然后我们找到"a",把它替换成\a,由于\是java转义字符,所以想表达\a必须写成"\\a",第一个反斜线将第二个反斜线转义成普通字符串。

三个替换表达式,只有第一个replace函数的结果是正确的,问题出在哪呢?

replaceAll和replaceFirst要求第一个参数是正则表达式,"a"既能理解成字符串a,也可以理解成正则表达式a,所以第一个参数没问题。

问题就出在第二个参数上,如果读者仔细阅读replaceAll函数的注释,会发现有如下说明:

Note that backslashes (\) and dollar signs ($) in the replacement string may cause the results to be different than if it were being treated as a literal replacement string; see Matcher.replaceAll. Use java.util.regex.Matcher.quoteReplacement to suppress the special meaning of these characters, if desired.

由于replaceAll和replaceFirst的第一个参数是正则,所以我们可以在第二个参数中做些小花样,比如有这样一个需求:把源字符串中的a替换成a后边紧邻的字符,代码如下:

1 System.out.println("abac".replaceAll("a(\\w)", "$1$1")); //bbcc
2 System.out.println("abac".replaceFirst("a(\\w)", "$1$1")); //bbac

正则的含义假设读者可以读懂,可以看出,在第二个参数中,可以用$符号获取分组的内容,本例中用$1取到了第一个分组的内容,即a后边紧邻的字符。

因此,$符号在第二个参数中是有特殊含义的,乱写会报错:

1 System.out.println("abac".replaceAll("a(\\w)", "$")); //Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 1

那假如我就想替换成$呢?这就需要转义字符:

1 System.out.println("abac".replaceAll("a", "\\$")); //$b$c

到这,读者可能会恍然大悟,原来反斜线在第二个参数中也有特殊含义(转义),所以如果我们想表达反斜线,就必须再转义一次:

1 System.out.println("abac".replaceAll("a", "\\\\a")); //\ab\ac
2 System.out.println("abac".replaceFirst("a", "\\\\a")); //\abac

简单理解一下,"\\\\a"中前边的反斜线分别转义后边的反斜线,让后边的反斜线就是普通字符串,这样在java内存中看到的字符串就是"\\a",然后replaceAll函数在处理时,再用前边的反斜线转义后边的反斜线,来表达后边的反斜线就是普通字符串,不是用来转义$的,最终内存中的字符串就是"\a",这样才可以成功将a替换成\a。

转义的问题确实纠结,通过本文,笔者希望读者以后使用这些函数时,能够保持清醒,能够意识到参数中的特殊字符,避免写出定时炸弹。

replace、replaceAll、replaceFirst的更多相关文章

  1. replace、replaceAll、replaceFirst的区别详解

    String s = "my.test.txt"; System.out.println(s.replace(".", "#")); Sys ...

  2. java字符串的替换replace、replaceAll、replaceFirst的区别详解

    如果不是刚刚复习了下正则表达式,我可能也不会注意到,原来String的replaceAll跟replaceFirst用到了正则表达式! 不多解释,看代码: String s = "my.te ...

  3. JAVA字符串的替换replace、replaceAll、replaceFirst的区别解析。

    String str = "i.like.cat"; System.out.println(str.replace(".", "!")); ...

  4. java字符串的替换replace、replaceAll、replaceFirst的区别

    看代码: String s = "my.test.txt"; System.out.println(s.replace(".", "#")) ...

  5. append、replace、replaceAll、indexof、lastIndexOf、substring的用法

    1.append StringBuffer buf = new StringBuffer("Hard "): String  aString  =  "Waxworks& ...

  6. java--字符串替换replace,replaceAll,replaceFirst

    1.字符串替换,replace string s="abcdfersabcdsgacabc"; 将字符串中的abc替换成bdf s.replace("abc", ...

  7. Java字符串替换函数replace、replaceFirst、replaceAll

    一.replace(String old,String new) 功能:将字符串中的所有old子字符串替换成new字符串 示例 String s="Hollow world!"; ...

  8. Excel函数——DATE、SUBSTITUTE、REPLACE、ISERROR、IFERROR

    1.DATE DATE 函数返回表示特定日期的连续序列号.例如,公式 =DATE(2008,7,8) 返回 2008-7-8或39637,取决于单元格格式,但空单元格计算和默认为日期格式. DATE也 ...

  9. 05_整理String类的Length()、charAt()、 getChars()、replace()、 toUpperCase()、 toLowerCase()、trim()、toCharArray()使用说明

    Question: 整理String类的Length().charAt(). getChars().replace(). toUpperCase(). toLowerCase().trim().toC ...

随机推荐

  1. Java生成带logo 的二维码

    这个工具类主要实现了两点功能: 1. 生成任意文链接的二维码. 2. 在二维码的中间加入图像. 主要实现步骤: 第一步: 导入QR二维码3.0 版本的core包和一张jpg图片(logo). core ...

  2. core.async中go的作用研究

    (defmacro go "Asynchronously executes the body, returning immediately to the calling thread. Ad ...

  3. 【POI2007】【Bzoj 1103】大都市meg

    http://www.lydsy.com/JudgeOnline/problem.php?id=1103 在线查询某点到根节点的点权和,参考DFS序&欧拉序列,用树状数组维护即可O(nlogn ...

  4. edittext 底线颜色

    <style name="Custom.Widget.EditView" parent="Widget.AppCompat.EditText" > ...

  5. [Codeforces 986E] Prince's Problem

    [题目链接] https://codeforces.com/contest/986/problem/E [算法] X到Y的路径积 , 可以转化为X到根的路径积乘Y到根的路径积 , 除以LCA到根的路径 ...

  6. JS动态加载JS

    1.直接document.write <script language="javascript">     document.write("<scrip ...

  7. vue项目开发中踩过的坑

    一.路由 这两天移动端的同事在研究vue,跟我说看着我的项目做的,子路由访问的时候是空白的,我第一反应是,不会模块没加载进来吧,还是....此处省略一千字... 废话不多说上代码 路由代码 { pat ...

  8. mysql百万数据分页查询速度

    百万数据测试 ,; 受影响的行: 时间: .080ms ,; 受影响的行: 时间: .291ms ,; 受影响的行: 时间: .557ms ,; 受影响的行: 时间: .821ms ,; 受影响的行: ...

  9. Windows 和 Linux 上Redis的安装守护进程配置

    # Windows 和 Linux 上Redis的安装守护进程配置 Redis 简介 ​ Redis是目前最常用的非关系型数据库(NOSql)之一,常以Key-Value的形式存储.Redis读写速度 ...

  10. 学习http协议的三次握手和四次挥手 ~~笔记

    http协议是基于tcp协议的  所以应该说是tcp协议的三次握手和四次挥手 SYN:请求建立连接,并在其序列号的字段进行序列号的初始值设定.建立连接,设置为1 FIN:用来释放一个连接.FIN=1表 ...