正则表达式

1. 匹配单个字符

1.1 任意字符

. 可以匹配任意单个除了换行符的字符。
例:

机器学习
链接: https://pan.baidu.com/s/1o9hlR5o 密码: 6iih

.

机器学习
链接: https://pan.baidu.com/s/1o9hlR5o 密码: 6iih

1.2 特殊字符(转义)

假如对这个例子,我们像匹配"pp."

napp.txt napptxt makk.txt

如果使用 pp.,匹配结果为:

napp. txt napptxt makk.txt

如果要匹配 .就要使用转义字符

pp\.

napp. txt napptxt makk.txt

2. 匹配一组字符

可以使用 [] 来定义一个字符集合,用于匹配属于该集合的字符

[mn]a

napp. txt napptxt makk.txt

2.1 使用字符区间

对于文本:

nam.txt na1.txt ma4.txt mb.txt

像要匹配如“m或n a 数字”的话,可以使用字符区间:

[mn]a[0-9]

nam.txt na1.txt ma4.txt mb.txt

字符区间准确而言是在ASCII中的子区间,因此可以是:

  • A-Z
  • a-z
  • 0-9
  • A-F

另外注意两点:

  • - 只在 [] 中才有特殊含义,所以一般使用是不需要转义
  • 不要出现类似 [3-1] 这种反序的区间

2.1.1 匹配中文字符

[\u4e00-\u9fa5]

2.2 取非匹配

可以在 [] 中的开头使用 ^ 字符表示取反操作:

[mn]a[^0-9]

nam.txt na1.txt mb.txt

另外有两点:

  • ^ 将对 [] 中所有字符取反,而非仅仅是它后面的那个
  • ^ 要放在开头

3. 元字符

3.1 转义问题

元字符指的是那些有着特殊含义的字符,如 .[] 等。不能使用这些元字符匹配其字面字符,必须使用转义。比如对于:

int[] arr = new int[5];
arr[0] = 1;
arr[1] = 2;

如果使用 arr[[0-9]] 试图匹配的话什么都匹配不到,必须要:

arr\[[0-9]\]

int[] arr = new int[5];
arr[0] = 1;
arr[1] = 2;

同理,比如我们希望把windows风格的路径变为Unix风格的。 > C:

如果使用 \ 的话什么都匹配不到,必须使用 \\

3.2 空白字符

常用的空白字符包括:

\t, \n, \r, \f(换页符), \v(垂直制表符)

可以使用 \s 来表示上面所有符号的集合,等价于 [\t\n\r\f\v]
另外 \S 表示所有非空白符,等价于 [^\t\n\r\f\v]

3.3 数字

  • \d: 等价与[0-9]
  • \D: 等价与[^0-9]

3.4 有效英文字符

  • \w: 等价于[0-9A-Za-z_](数字字母下划线)
  • \W

4. 重复匹配

4.1 ?+*

  • ?: 匹配零次或一次
  • *: 匹配零次或多次
  • +: 匹配一次或多次

4.2 使用{}

  • 指定次数
    使用 {n} 表示重复 n
  • 设定区间
    • 使用 {m, n} 表示最少重复 m 次,最多 n
    • 使用 {m,} 表示至少重复 m

4.3 防止过度匹配

以上所有的重复匹配,都默认是贪婪型的,它们会尽可能的匹配多的字符而不是在第一个匹配位置就结束

A <B>utf-8</B> B <B>GBK\</B>

<B>.*</B>

A <B>utf-8</B> B <B>GBK</B>

为了改为“懒惰型”,只需要在最后加上?即可:

  • *?
  • +?
  • {m, }?

<B>.*?</B>

A <B>utf-8</B> B <B>GBK</B>

5. 位置匹配

5.1 单词边界

The cat scattered his food

cat

The cat scattered his food

使用\b可以限定单词边界,他匹配的是一个位置。

\bcat\b

The cat scattered his food

5.2 字符串边界

  • ^
  • $

6. 子表达式

使用()括在一起地被视为一个子表达式,是一个整体。

7. 回溯引用

回溯引用指的是可以引用待匹配字符串中其中一部分,为了具体说明首先我们来看一个例子。

假如我们有下面这段文本:

<h1>ddd<h1>
<h1>ddd<h2>

我们希望能够匹配到符合规则的HTML标签,也许可以这样:

<h\d>.*?<h\d>

很遗憾,这样做会把第二个不合法的标签也囊括进来:

<h1>ddd<h1>
<h1>ddd<h2>

所以我们需要能够引用之前能匹配的子串,具体做法就是使用回溯引用:

(<h\d>).*?\1

结果为:

<h1>ddd<h1>
<h1>ddd<h2>

这里使用了子表达式和回溯引用的方法,\1表示引用第一个子表达式。可以把它想象成一个变量,使用“变量名”\1来引用。

一般而言,回溯引用常常从1开始计数(\1, \2等等)

8. 零宽断言

零宽断言是正则表达式的一种方法,用于查找在某些内容(但并不包括这些内容)之前或者之后的东西,也就是说他们像 \b^ (匹配输入字行首),$ (匹配输入字行尾)那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。

断言用来声明一个应该为真的事实,正则表达式中只有当断言为真时才会继续进行匹配。

8.1 零宽度正预测先行断言

(?=exp) 叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp

比如 \b\w+(?=ing\b) ,匹配以ing结尾的单词的前面部分(除了ing以外的部分)。

I'm singing while you're dancing

\b\w+(?=ing\b)

I'm singing while you're dancing

8.2 零宽度正回顾后发断言

(?<=exp) 也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp

比如 (?<=\bre)\w+\b 会匹配以re开头的单词的后半部分(除了re以外的部分)。

reading a book

(?<=\bre)\w+\

reading a book

不过这个特性不一定每个实现都支持