正则表达式基础
字符匹配
如果你想在一段文字中查找hi,使用正则表达式hi。这时最简单的正则表达式了,它可以精确匹配字符 h 和字符 i 。
如果你想在一段文字中查询a、b、c中的任一个字符,可以使用正则表达式[abc],在正则表达中使用中括号括起来多个字符来表示匹配其中任何一个字符;在中括号中还能使用 - 来表示连续的多个字符,如:[0-9]表示匹配任何一个数字字符。
那如果我想匹配字符 [、-该怎么处理呢,这是可以使用正则表达式中的转义字符 \ 来转义,\[、\- 就可以用来匹配字符[、- 了。
想要表示任意一个字符,为了方便,正则表达式中还有一种表示方式 \d。\d 是正则表达式提供的元字符;除了元字符\d来表示任意数据,还有\s 表示空白字符,\w表示词字符。
其他一些常用的字符类如下:
正则表达式 | 含义 |
. | 任意字符 |
[abc] | 字符集。匹配包含的任一字符。 |
[^abc] | 反向字符集。匹配未包含的任何字符。其中位于中括号首位的^表示非的意思。 |
[a-z] | 字符范围。匹配指定范围内的任何字符。要求-前面的字符的ASCII值必须小于-后面字符的ASCII值。 |
\d | 数字字符,等效于[0-9] |
\D | 非数字字符,等效于[^\d] |
\w | 词字符,等效于:[a-zA-Z0-9_] |
\W | 非词字符,等效于[^\w]、[^a-zA-Z0-9_] |
\s | 空白字符(空格,tab、换行,换页和回车)。等效于[\f\n\r\t\v] |
\S | 非空白字符,等效于[^\s] |
限定符
上面的字符类只能表示任一个字符,如果表示字符连续出现多次呢?正则表达式中可以使用如下几种限定符:
表示方式 | 含义 |
{n} | n 是非负整数。正好匹配 n 次 |
{n,m} | m 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。 |
{n,} | n 是非负整数。至少匹配 n 次。 |
? | 零次或一次匹配前面的字符或子表达式。等效于{0,1} |
+ | 一次或多次匹配前面的字符或子表达式。等效于{1,} |
* | 零次或多次匹配前面的字符或子表达式。等效于{0,} |
特别注释的时,只有紧随出现在字符或字符组后面时,才是定义字符次数的含义;例如:?只有在紧随在字符或者字符组后面时,才表示字符或则字符组出现0次或1次的含义,如过?紧随出现在限定符后面时({n}?、+?、??、*?),其含义为匹配模式中的非贪心模式
字符组
可以使用小括号()来表示一组,再配合上面的限定符,可以限定改组字符重复出现的次数,如:(abc){2},表示abc这组三个字符重复出现2次,即abcabc。
匹配模式
匹配模式描述了一个正则表达式中限定符吸收输入字符的方式。
- 贪婪型 :默认的匹配模式,在能匹配成功的前提下,尽可能多的匹配字符。
- 勉强型 :在能匹配成功的前提下,尽可能少的匹配字符
- 占有型 :目前,这种类型只在Java中才有;当正则表达式被应用于字符串时,他会产生相当多的状态,以便在匹配失败时可以回溯(前面两个模式都是以匹配成功为前提的,所以在匹配过程中可能要回溯)。而占有型并不保存这些中间状态,因此他们可以放置回溯。它常常用于防止正则表达式失控,因此可以使正则表达式执行起来更有效(可以参考一个正则表达式引发的血案)
各个模式中限定符的表示,其中X为字符或者字符组
贪婪型 | 勉强型 | 占有型 | 如何匹配 |
X{n} |
X{n}? | X{n}+ |
恰好n次X |
X{n,m} |
X{n,m}? | X{n,m}+ |
X至少n次,且不超过m次 |
X{n,} |
X{n,}? | X{n,}+ |
至少n次 |
X? |
X?? | X?+ | 一个或者零个X |
X+ |
X+? | X++ | 一个或则多个X |
X* |
X*+ | X*+ | 零个或则多个X |
边界匹配符
正则表达式中的边界有两种,一位字符边界,另一个为行边界
表示方式 | 含义 |
\b | 词的边界,即字符与空格间的位置 |
\B | 非词的边界 |
^ | 一行的起始, |
$ | 一行的结束 |
\G | ??? 前一个匹配的结束 ??? |
零宽断言
又叫 正反向预搜索,可以认为是一种特殊的边界匹配符,用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足exp表达式的条件
表示方式 | 位置 | 含义 |
(?=exp) | 写在目标字符串的右边 | 右边必须满足exp表达式 |
(?!exp) | 写在目标字符串的右边 | 右边必须不满足exp表达式 |
(?<=exp) | 写在目标字符串的左边 | 左边必须满足exp表达式 |
(?<!exp) | 写在目标字符串的左边 | 左边必须不满足exp表达式 |
需要注意的是:预搜索的内容和exp表达式,都并非时固定值,也可以用正则表达式来表达式
比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配sing和danc。
反向引用
前面我们有讲过字符组的概念,就是使用小括号指定一组字符,也就是一个子表达式,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。
默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。
使用\num (num必须>=1) 就能表示出第num个括号里的内容了,但这部分内容必须再前面出现过,也就是说num不能大于分组组号。
使用\0 对应整个正则表达式匹配的内容
分组除了默认的组号外,正则表达式还允许你给组起名字,可以使用(?<name>)来给一个分组命名,引用是使用\k<name>来引用一个命名分组
非捕获分组
上面说了要想引用分组,必须要用分组编码,但是并不是所有括号括起来的字符都是有组号的,没有组号的分组,也叫做非捕获分组
几种常见的非捕获分组:
类型 | 表示方式 | 含义 |
非捕获分组 | (?:exp) | 匹配exp,不捕获匹配的文本,也不给分组分配组号 |
零宽断言 | (?=exp) | 详见零宽断言 |
(?<=exp) | 详见零宽断言 | |
(?!exp) | 详见零宽断言 | |
(?<!exp) | 详见零宽断言 | |
注释 | (?#comment) | 给人看的注释 |
标志
可以使用正则表达式提供的选项标志来定制表达式引擎的工作方式
标志的开始使用 (?标志) 结束使用 (?-标识) ,如果一个表达式中既有某个标志的开始,也有其结束,表示被从标志开始到结束之间的表达式,表达式引擎将要使用该标志指定的方式工作。
如果某个标志只有开始没有结束,表示该标志的作用范围是标志的开始到表达式的结尾
常见的标志
开始表示方式 | 结束表示方式 | 含义 |
(?i) | (?-i) | 匹配过程中忽略大小写 |
(?u) | (?-u) | 将忽略大小写的范围扩大到整个unicode字符集,需要与(?i)一起使用 |
(?m) | (?-m) | 匹配过程中将换行符(\n)也看做一行的结尾 |
(?s) | (?-s) | 允许 .(点字符)匹配换行符 |
(?x) | (?-x) | 忽略正则表达式中的非转义空白字符(即不包含\s等转义空白字符) |
Java中使用正则表达式
Java中的正则表达式的转义
下面时Java编程思想中的一段描述:
如果在其他语言中使用过正则表达式,那你立刻就能发现Java对反斜线 \ 的不同处理。在其他语言中, \\ 表示“我想要在正则表达式中插入一个普通的(字面上的)反斜线,请不要给它任何特殊的意思。” 而在Java中, \\ 的意思时“我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意思。” 例如,如果你想表示一位数字,那么正则表达式应该时 \\d,如果你想插入一个普通的反斜线,则应该这样 \\\\ 。
菜鸟教程的另一段描述:
根据 Java Language Specification 的要求,Java 源代码的字符串中的反斜线被解释为 Unicode 转义或其他字符转义。因此必须在字符串字面值中使用两个反斜线,表示正则表达式受到保护,不被 Java 字节码编译器解释。例如,当解释为正则表达式时,字符串字面值 "\b" 与单个退格字符匹配,而 "\\b" 与单词边界匹配。字符串字面值 "\(hello\)" 是非法的,将导致编译时错误;要与字符串 (hello) 匹配,必须使用字符串字面值 "\\(hello\\)"。
Java对正则表达式的支持
Java对正则表达式的支持类在 java.util.regex 包中,主要相关类为:Pattern类 和 Matcher类
其中Pattern的对象是一个正则表达式的编译表示,而Matcher的对象是对输入字符串进行解释和匹配操作的引擎
Pattern类常用方法
Pattern类没有public的构造方法,必须使用下面两个静态方法构造pattern对象
Matcher类常用方法
参考
菜鸟教程 https://www.runoob.com/java/java-regular-expressions.html
正则表达式30分钟入门教程 https://deerchao.cn/tutorials/regex/regex.htm
Java编程思想 4
JAVA 正则表达式的三种模式 https://blog.csdn.net/bigtree_3721/article/details/50448952
一个由正则引发的血案 https://www.cnblogs.com/study-everyday/p/7426862.html
沙 Java高手修炼之道06-全网最详细正则表达式 https://www.bilibili.com/video/BV1kU4y1V7nV?p=1
韩 Java 正则表达式专题 -正则 https://www.bilibili.com/video/BV1Eq4y1E79W?p=1