[正则表达式] Basic

Posted by Dongbo on November 5, 2019

一段时间没用连之前自己写的匹配模式都看不懂了。不过本来学得也不咋地,重新学习。示例使用Java Pattern/Matcher类验证。

这里有一份不知哪里来的正则表达式手册

元字符

   
^ 匹配字符串的开始位置
$ 匹配字符串的结束位置
* 匹配前面的表达式0次或多次, “zo*“可匹配”z”, “zo”, “zoo”等, 等价于{0,}
+ 匹配前面的表达式1次或多次, “zo+”可匹配”zoo”, 不可匹配”z”, 等价于{1,}
? 匹配前面的表达式0次或1次, “zo”可匹配”z”, “zo”, 不可匹配”zoo”, 等价于{0,1}
? (懒惰匹配)符号”?”跟在其他限制符如*, +, ?, {n}, {n,m}后时, 匹配尽可能短的字符串, 例如: “ooo,ooo”, 模式”o+?”匹配单个”o”共6个, 而”o+”匹配得到两个”ooo”
. 匹配除”\n”以外的任意字符
x|y 匹配x或y
     
\b 匹配单词边界-bound “er\b”可以匹配”hacker die”中的er,不能匹配”verb”中的er
\B 匹配非单词边界 “er\b”可以匹配”verb”中的er,不能匹配”hacker die”中的er
\d 匹配一个数字字符-digit 等价于[0-9]
\D 匹配一个非数字字符 等价于[^0-9]
\s 匹配一个任意的空白字符-space 等价于[\f\n\r\t\v] (按顺序分为换页符, 换行, 回车, 制表符, 垂直制表符)
\w 匹配一个包括下划线的任意单词字符-word 等价于[A-Za-z0-9_] 注意包含下划线
\W 匹配任何非单词字符 [^A-Za-z0-9_]
\*num* 正整数num表示第几个分组的引用 (s)-(a)-\2匹配”s-a-a”,\1得到第一个分组,这里是”s”,\2是第二个分组)

获取分组

使用小括号捕获分组, 自左向右, 第一个分组为1, 第二个为2, 以此类推

   
(pattern) 匹配并捕获这一分组,之后可以通过$num引用,若有嵌套, 则按照左括号出现的顺序捕获
(?:pattern) 匹配但不捕获
(?<name>pt) 给分组命名,用\k<name>在模式中引用, 例如用(?<myword>\w)\k<myword>捕获两个连续的单词字符
(?=pattern) 正向预查, pattern部分不在匹配范围内
Java(?=6)匹配”Java6, Java8”中的第一个”Java”, 不包含”6”
(?!pattern) 正向否定预查
(?<=pattern) 反向预查
(?<=J)a匹配”Java6, Java7”的结果为Java6, Java7
(?<!pattern) 反向否定预查

正/反向预查部分例子来自于https://my.oschina.net/lxpan/blog/27907

Q: 为什么要使用(?:pattern)匹配但是不捕获分组?
……为什么呢? 是不是存在可以不捕获但是必须分组的情况? 那么这种情况下就算捕获了会出现什么影响呢?

这里说捕获组是要占用内存的。那么答案应该是为了节省内存降低开销吧。

Class Matcher Method  
String group(int group)
Returns the input subsequence captured by the given group during the previous match operation.
String group(String name)
Returns the input subsequence captured by the given named-capturing group during the previous match operation.

补充:使用Java进行验证的时候,从API可以看出,每个捕获分组都对应一个String,验证了上述说法。


实际上组号分配过程是要从左向右扫描两遍的:第一遍只给未命名组分配,第二遍只给命名组分配--因此所有命名组的组号都大于未命名的组号

对于文本

1
一段时间没用连之前自己写的匹配模式都看不懂了

模式一段(.*)连(.*)匹配(.*)(?<n1>懂)(.*)匹配得到一段时间没用连之前自己写的匹配模式都看不懂了

$1为"时间没用", $2为"之前自己写的", $3为"模式都看不", $4为"懂"(与$<n1>相同。Java中获取命名分组使用String group(String name), 获取分组数groupCount()),$5为"了"。与上面说法不符

嵌套分组捕获

前面说了,嵌套是按照左括号从左到右出现的先后来捕获的,下面是示例:

对于文本

1
2
3
4
a1a2ba2  
a1a2ba1  
a1a2ba1a2  
a1a2ba1a2b  

模式((a1(a2))b)\1匹配第4行a1a2ba1a2b
模式((a1(a2))b)\2匹配第3、4行的a1a2ba1a2
模式((a1(a2))b)\3匹配第1行a1a2ba2