本文链接 https://unmi.cc/understand-java-regex-backslash/, 来自 隔叶黄莺 Unmi Blog

Java 语言里的几大变革,一为 jdk1.4 引入的正则表达式,jdk1.5 引入的泛型。没有泛型之前有不少人曾想方设法从编译器入手让 Java 支持泛型。说到泛型  Perl 无疑是该方面的佼佼者,虽然我们不要求 Java 的正则表式能像 Perl 那样可以用来写诗,但至少能有 JavaScript 好用些,可是还不如。JavaScript 里 // 两斜线一框就是一个模式,分组和后向引用更方便,当然前面那两家伙是动态的,不太好比。

复杂的用法不说,且说 Java 的正则表达式在匹配点(.)  和斜杠(\),表达式要分别写作 \\. 和 \\\\,难看些,不好理解。幸好还有些人记住了,匹配点(.) 或  {、[、(、?、$、^ 和 * 这些特殊符号要要前加双斜框,匹配 \ 时要用四斜杠,这确实能让你包走天涯的。那么为什么是这样呢,不是一个斜杠、三个或更多呢,所以知其然还要知其所以然,这样才能每次心中有数,方能以一变应万变。

首先,Java 的正则表达式语法说明参见:https://download.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html

用最简单的例子来说明问题吧,不创建 Pattern、Matcher 等对象,就看 String 对象的 replaceAll(String regex, String replacement),它第一个参数接收的就是一个正则表达式,我们可以在 IDE 里的调试器中看 "a.b".replaceAll(".","") 能不能得到你期望的结果。

先说为什么像点号(其他的特殊符号还有引号中的 "{、[、(、?、$、^ 和 *")前面要加双斜杠,注意逗号(,) 不是这一类特殊字符,因为它只会出现在中括号或花括号中。

显然,如果直接执行

"a.b".replaceAll(".","");  //返回空字符串

得到的值不是你想要的结果,成空字符串了,因为点号 "." 匹配了所有的字符,那要只匹配点号该如何呢,对的,双斜杠

"a.b".replaceAll("\\.","");  //对的,得到的是 ab

那为什么是双斜杠呢?这个很简单,因为点号(.),是个特殊字符,所以它前面需要需要加个斜杠给它转义,你要真只用一个斜杠来转义,问题就来了,提示你:

Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\),也就是 Java 不认 \. 序列,所以还需要前面再加一道杠给其后的斜杠转义出一个斜杠给点号(.) 用,也就是在 Java 字符串看起来是 “\\.”, 但作为正则表达式来说就是 “\.”,这于其语言的正则表达式是一致的。

也就是说 Java 的正则表达式字符串有两层次的意义,那就是 Java 字符串转义出符合正则表达式语法的字符串,“\\.”, 转义后交给正则表达式的就是 “\.”,这是符合传统的。因为我们平时字符串转义后直接用于输出,所以带来不少误解,这里的最终的正则表达式就是 Java 字符串的输出。

 

细心的同志一定能看到在调试器里的显示,看我们写成的“\\.”, 在调试器里显示的是 “\\\\.”,说的是如果我们要得到 “\\.”,这样的输出那 Java 的字符串就必须写成 “\\\\.”, 两个斜杠转义出一个斜杠。

好的,理解了上面的由来,我们来看看用四个斜杠来匹配一个斜杠的原理。主要原因是斜杠 \ 本身就是用于转义别的字符的,当然它的架子不是一般的大。因为正则表达式串就是 Java 字符串的输出,正常思维在正则表达式里匹配斜杠用 “\\”, 那么在 Java 程序里向控制台输出 “\\”双斜杠该如何写呢,对了,就是 “\\\\”,就这么简单。

 

再一次从错误里找下原因吧,假如我们写成:

"a\\b".replaceAll("\", "");

报什么错呢?String literal is not properly closed by a double-quote,因为斜杠把其后的双引号给转义了,当然字符串是未结束。再给它加个斜杠又如何呢?

"a\\b".replaceAll("\\", "");

Java 的语法是通过了,但是执行正则表达式不干了,你转义出来的交给正则表达式的一个斜杠,叫它情何以堪,该去转义谁呢?所以运行时异常报 An exception occurred: java.util.regex.PatternSyntaxException。

如果写成三个斜杠呢?

"a\\b".replaceAll("<a>\\\</a>", ""); //与单个斜杠是一样的异常,挂单的斜杠把双引号给转义了

所以这样推来推去也是该写成

"a\\b".replaceAll("<a>\\\\</a>", "");

对于正则表达式看到的就是 “\\”,哪种语言的正则表达式要的也是这个,也是第一个斜杠转义了第二个,第三个转义了第四个,最终就是 “\\”,正则表达式里转互相转义一下就是 “\”了。

我原来理解还只是停留下转义啊,再转义的基础上,随着写这篇才更加理解到其中要义的,才发现,原来 Java 的正则表达式和其他语言的正则表达式语言是统一的。只要记住一点,你要想的正则表达式字符串是什么,而正则表达式字符串就是 Java 字符串的的输出结果,你就知道应该怎么写了

最后来看下 Eclipse 调试器里仅匹配单个斜杠时,IDE 里显示的有多疯狂:

这让你体验到四个斜杠又何其多也。注:全文中的斜框标准意义上应该叫做反斜杠,在此就不作全文替换了。

posted @ 2017-09-13 19:44 PianoCoder 阅读(7759) 评论(1) 推荐(0) 编辑
摘要: @Test public void testMap2List() throws Exception{ Map<String, String> map = new HashMap<String, String>(); map.put("1", "AA"); map.put("2", "BB"); ma 阅读全文
posted @ 2016-02-17 19:16 PianoCoder 阅读(94807) 评论(2) 推荐(2) 编辑
摘要: 【git 删除本地分支】git branch -D br【git 删除远程分支】git push origin :br (origin 后面有空格)git代码库回滚: 指的是将代码库某分支退回到以前的某个commit id【本地代码库回滚】:git reset --hard commit-id :回... 阅读全文
posted @ 2015-12-31 17:20 PianoCoder 阅读(211829) 评论(2) 推荐(0) 编辑
摘要: 基于HTTP协议的Web API是时下最为流行的一种分布式服务提供方式。无论是在大型互联网应用还是企业级架构中,我们都见到了越来越多的SOA或RESTful的Web API。为什么Web API如此流行呢?我认为很大程度上应归功于简单有效的HTTP协议。HTTP协议是一种分布式的面向资源的网络应... 阅读全文
posted @ 2015-12-08 15:36 PianoCoder 阅读(323) 评论(0) 推荐(0) 编辑
摘要: 1 事务的传播属性(Propagation)1) REQUIRED ,这个是默认的属性Support a current transaction, create a new one if none exists.如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。被设置成这个级别时,会... 阅读全文
posted @ 2015-09-08 10:10 PianoCoder 阅读(605) 评论(0) 推荐(0) 编辑
摘要: 本文转载自:http://www.linuxidc.com/Linux/2013-12/93690.htm#0-tsina-1-14812-397232819ff9a47a7b7e80a40613cfe1 Java中有两种实现多线程的方式。一是直接继承Thread类,二是实现Runnable接... 阅读全文
posted @ 2015-09-01 11:20 PianoCoder 阅读(1155) 评论(0) 推荐(0) 编辑
摘要: Oracle的分页查询语句基本上可以按照本文给出的格式来进行套用。(一)分页查询格式:SELECT*FROM(SELECTA.*,ROWNUMRNFROM(SELECT*FROMTABLE_NAME)AWHEREROWNUM=21其中最内层的查询SELECT*FROMTABLE_NAME表示不进行翻... 阅读全文
posted @ 2015-08-24 19:27 PianoCoder 阅读(4168) 评论(0) 推荐(0) 编辑
摘要: 作者: 阮一峰日期: 2009年8月30日转载地址:http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。... 阅读全文
posted @ 2015-08-10 19:10 PianoCoder 阅读(253) 评论(0) 推荐(0) 编辑
摘要: ◆ 文件处理命令:file、mkdir、grep、dd、find、mv、ls、diff、cat、ln;系统信息存放在文件里,文件与普通的公务文件类似。每个文件都有自己的名字、内容、存放地址及其它一些管理信息,如文件的用户、文件的大小等。文件可以是一封信、一个通讯录,或者是程序的源语句、程序的数据,甚... 阅读全文
posted @ 2015-07-23 11:54 PianoCoder 阅读(931) 评论(0) 推荐(0) 编辑
摘要: Linux必学的60个命令Linux提供了大量的命令,利用它可以有效地完成大量的工 作,如磁盘操作、文件存Linux提供了大量的命令,利用它可以有效地完成大量的工作,如磁盘操作、文件存取、目录操作、进程管理、文件权限设定等。所以,在Linux系统上工作离不开使用系统提供的命令。要想真正理解Linux... 阅读全文
posted @ 2015-07-23 11:50 PianoCoder 阅读(5584) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示