令人抓狂的代码 - 万能正则表达式.*陷阱

简介:

令人抓狂的代码 - 万能正则表达式.*陷阱

先尝试执行下面的代码:

 
 
  1. println("play \n scala".matches(".*")) 

你没看错,打印结果是false。正如键盘布局一样,这是由于一个历史问题导致的。早期的正则表达式工具是基于行处理文本的,所以.匹配的是除换行符以外的任意字符。大多数编程语言在设计正则表达式时沿用了这个传统,但是提供一个选项用于开启"点号匹配换行符"模式。

Java提供了两种方式开启"点号匹配换行符"模式,第一种方式是在构建Pattern对象时指定匹配模式:

 
 
  1. val p = Pattern.compile(".*", Pattern.DOTALL) 
  2.  
  3. println(p.matcher("play\nscala").matches()) // true 

另一种方式是在正则表达式开始位置指定嵌入模式修饰符(embedded mode modifier),这也是一种比较通用的方式:

 
 
  1. println("play\nscala".matches("(?s).*")) // true 

Pattern.DOTALL和(?s)是等价的。

Java常用的匹配模式有以下几种:

1) Pattern.DOTALL

启用dotall模式。在dotall模式下,模式中的.匹配任意字符,包括换行符。在默认情况下(即未启用dotall模式),.不匹配换行符。等价于修饰符(?s)。

 
 
  1. val p = Pattern.compile(".*", Pattern.DOTALL) 
  2. val m = p.matcher("play\nscala"
  3. println(m.matches()) 
  4. // 输出 
  5. true 

2)Pattern.MULTILINE

启用多行匹配模式。在多行匹配模式下,模式中的^和$将逐次匹配每一行的行首和行尾。在默认情况下(即未启用多行匹配模式),^和$将匹配整个字符串的首部和尾部。等价于修饰符(?m)。

 
 
  1. val p = Pattern.compile("^.*$", Pattern.MULTILINE) 
  2. val m = p.matcher("play\nscala"
  3. while (m.find()) { 
  4.   println("find: " + m.group(0)) 
  5.  
  6. // 输出 
  7. find: play 
  8. find: scala 

3) Pattern.UNIX_LINES

启用Unix换行模式,使用"\n"标识每一行的末尾,等价于修饰符(?d)。

 
 
  1. val p = Pattern.compile("^.*$", Pattern.UNIX_LINES | Pattern.MULTILINE) 
  2. val m = p.matcher("play\r\nscala"
  3. while (m.find()) { 
  4.   println("find: " + m.group(0).length) 
  5. // 输出 
  6. find: 5 
  7. find: 5 

输出的两个结果长度都为5,原因是play末尾还有一个字符\r。

4)Pattern.CASE_INSENSITIVE

启用大小写不敏感匹配,等价于修饰符(?i)。

 
 
  1. val p = Pattern.compile("^S.*A$", Pattern.CASE_INSENSITIVE) 
  2. val m = p.matcher("scala"
  3. println(m.matches()) 
  4. // 输出 
  5. true 

5)Pattern.LITERAL

启用字面(literal)模式解析,模式中的元字符和转义字符将按照普通字符解析。

 
 
  1. val p = Pattern.compile(".*", Pattern.LITERAL) 
  2. val m = p.matcher("scala"
  3. println(m.matches()) 
  4. // 输出 
  5. false 

6)Pattern.COMMENTS

正则表达式中允许出现空白符(whitespace)和注解(comments),空白符会被忽略,以#开头的注解行也将被忽略,等价于修饰符(?x);

 
 
  1. val p = Pattern.compile(" .* ", Pattern.COMMENTS) 
  2. val m = p.matcher("scala"
  3. println(m.matches()) 
  4. // 输出 
  5. true 

注:有些编程语言(例如JavaScript)不支持嵌入模式修饰符(embedded mode modifier),这时可以使用另一种解决方案:

 
 
  1. [\s\S]* 

[\s]会匹配任意空白字符,[\S]而则会匹配[\s]不能匹配的任意字符。把这二者组合起来构成[\s\S],这样就会得到一个包含所有字符的字符组,其中也包含了换行符。


原文发布时间为:2017-10-24

本文作者:joymufeng

本文来自云栖社区合作伙伴“51CTO”,了解相关信息可以关注。

相关文章
正则表达式获取一串网址的域名段代码
正则表达式获取一串网址的域名段代码
用正则表达式限制input输入框只能输入整数的一段简单代码
要实现input框只能输入正整数,如果检测到输入其他类型的数据就直接为0;代码如下:
327 0
动手学正则表达式(含Python代码实践)(下)
动手学正则表达式(含Python代码实践)(下)
动手学正则表达式(含Python代码实践)(下)
动手学正则表达式(含Python代码实践)(上)
动手学正则表达式(含Python代码实践)(上)
动手学正则表达式(含Python代码实践)(上)
|
数据采集 Python
常用正则表达式最强汇总(含Python代码举例讲解+爬虫实战)
带大家学习正则表达式,并通过python代码举例讲解常用的正则表达式 最后实战爬取小说网页:重点在于爬取的网页通过正则表达式进行解析。
188 0
|
JavaScript 前端开发 Java
JavaScript正则表达式的模式匹配教程,并且附带充足的实战代码(四 | 完结)
我们继续来学习正则表达式吧,没有看过之前文章的小伙伴建议点击上方链接,从第一篇开始看,本系列文章适合从未接触过或不太了解正则表达式的人
188 0
|
JavaScript 前端开发 Java
JavaScript正则表达式的模式匹配教程,并且附带充足的实战代码(三)
我们继续来学习正则表达式吧,没有看过之前文章的小伙伴建议点击上方链接,从第一篇开始看,本系列文章适合从未接触过或不太了解正则表达式的人
122 0
|
JavaScript 前端开发 Java
JavaScript正则表达式的模式匹配教程,并且附带充足的实战代码(二)
我们继续来学习正则表达式吧,没有看过之前文章的小伙伴建议点击上方链接,从第一篇开始看,本系列文章适合从未接触过或不太了解正则表达式的人
173 0
|
JavaScript 前端开发 索引
JavaScript正则表达式的模式匹配教程,并且附带充足的实战代码(一)
其实我写这篇文章的话,主要是想自己重新复习一遍正则表达式。我们也知道正则表达式在很多语言中都是通用的,所以学好这个好处很多。接下来,就跟我一起来学习一下正则表达式,从0到入门吧。同时我会把文章分成多篇来讲解,欢迎大家持续订阅
100 0
一个利用正则表达式进行代码重构,去除冗余代码的例子
一个利用正则表达式进行代码重构,去除冗余代码的例子
307 0
一个利用正则表达式进行代码重构,去除冗余代码的例子

相关实验场景

更多