理解 Java 正则表达式怪异的 \\ 和 \\\\,让您见怪不怪
本文链接 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 里显示的有多疯狂:
这让你体验到四个斜杠又何其多也。注:全文中的斜框标准意义上应该叫做反斜杠,在此就不作全文替换了。
理解 Java 正则表达式怪异的 \\ 和 \\\\,让您见怪不怪的更多相关文章
- 关于 Java正则表达式中的Possessive数量修饰词的理解
关于 Java正则表达式中的Possessive数量修饰词的理解 正则表达式对于数量限定符如 ?, + , *, {n, m} 的匹配默认是贪婪模式,比如: a.*b 匹配 acbab 的结果是 ...
- 【转】java正则表达式
在Sun的Java JDK 1.40版本中,Java自带了支持正则表达式的包,本文就抛砖引玉地介绍了如何使用java.util.regex包. 可粗略估计一下,除了偶尔用Linux的外,其他Linu ...
- java正则表达式语法详解及其使用代码实例
原文地址 译者序(下载代码) 正则表达式善于处理文本,对匹配.搜索和替换等操作都有意想不到的作用.正因如此,正则表达式现在是作为程序员七种基本技能之一*,因此学习和使用它在工作中都能达到很高的效率. ...
- JAVA 正则表达式 (超详细)
(PS:这篇文章为转载,我不喜欢转载的但我觉得这篇文章实在是超赞了,就转了过来,这篇可以说是学习JAVA正则表达的必读篇.作者是个正真有功力的人,阅读愉快) 在Sun的Java JDK 1.40版本中 ...
- 转载:JAVA 正则表达式 (超详细)
在Sun的JavaJDK 1.40版本中,Java自带了支持正则表达式的包,本文就抛砖引玉地介绍了如何使用Java.util.regex包. 可粗略估计一下,除了偶尔用Linux的外,其他Linu x ...
- Java正则表达式语法
Java正则表达式 表达式意义: 1.字符 x 字符 x.例如a表示字符a \\ 反斜线字符.在书写时要写为\\\\.(注意:因为java在第一次解析时,把\\\\解析成正则表达式\\,在 ...
- Java正则表达式初学者使用法简介
在Java中使用正则表达式的方法非常多,最简单的就是和字符串一起使用.对于Java正则表达式初学者,在String中有四个方法可以使用正则表达式,本文正是介绍这四个方法来使用正则表达式来处理文本数据. ...
- Java正则表达式教程及示例
本文由 ImportNew - ImportNew读者 翻译自 journaldev.欢迎加入翻译小组.转载请见文末要求. [感谢 @CuGBabyBeaR 的热心翻译.如果其他朋友也有不错的原创或 ...
- [转载]java正则表达式
转载自:http://butter.iteye.com/blog/1189600 1.正则表达式的知识要点1.正则表达式是什么?正则表达式是一种可以用于模式匹配和替换的强有力的工具.2.正则表达式的优 ...
随机推荐
- git --mixed --soft --hard之间的区别
git reset --mixed:此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,只保留源码,回退commit和add信息git reset --soft:回退到某个 ...
- display:block、inline、inline-block的区别及应用案例
A.display:block就是将元素显示为块级元素. block元素的特点是: 1.总是在新行上开始: 2.高度,行高以及顶和底边距都可控制: 3.宽度缺省是它的容器的100%,除非设定一个宽度; ...
- Mac 提交代码到Github
然后在GitHub上创建版本库(Repository),在GitHub首页上,点击“Create a New Repository”,如下所示(为了便于后面演示,创建README.md这步暂不勾选): ...
- IOS Core Image之二
在上篇博客IOS Core Image之一中了解了下CIImage.CIFilter.CIContext三个类的使用,这篇了解下滤镜链(多滤镜)和人脸检测(不是人脸识别). 一.多滤镜 1.有些效果不 ...
- jQuery事件篇---基础事件
写在前面: 有一段时间未更新博客了,利用这段时间,重新看了<jQuery基础教程 第四版>和<锋利的jQuery 第二版>,这两本书绝对是jQuery入门非常好的书,值得多读几 ...
- Fask中的路由-模版-静态文件引用 及宏定义与表单
文档: flask: http://docs.jinkan.org/docs/flask/quickstart.html#redirects-and-errors jinja2 http://docs ...
- WPF实现夜间模式
背景 项目中设计了一个黑色主题,稍加改正也可作为夜间模式,效果图如下: 原理 由于项目中存在地图,而地图完全是由位图组成,不能直接改变背景色,所以我在内容上面放置了一个黑色的Border作为遮罩.可通 ...
- 4、构造方法、this、super
构造方法 构造方法引入 * A:构造方法的引入 在开发中经常需要在创建对象的同时明确对象的属性值,比如员工入职公司就要明确他的姓名.年龄等属性信息. 那么,创建对象就要明确属性值,那怎么解决呢?也就是 ...
- JAVA基础之——使用idea创建maven项目 以及使用tomcat本地调试springmvc
前言:关于这个话题网上有很多,本文旨在引导实战纠偏,理论偏少,如果按照步骤还不能达到本文目的,请留言. 1 环境准备 1.1 软件准备 idea:官方下载社区版,下载后安装 maven:Apache- ...
- 阿里巴巴的数据池DRUID
使用了阿里巴巴的数据池管理: 监控DB池连接和SQL的执行情况 https://github.com/alibaba/druid/wiki/常见问题 https://www.cnblogs.com ...