正则表达式

发表于:,更新于:,By Minary
大纲
  1. 1. what is 正则?
  2. 2. 先来几个简单的正则!
  3. 3. 元字符
  4. 4. 字符转义
  5. 5. 限定符
  6. 6. 字符类
  7. 7. 分枝条件
  8. 8. 分组
  9. 9. 反义
  10. 10. link

最近一直在忙于加班,已经连续两个星期996(9点上班9点下班星期六加班)了!
项目采用的是 TDD 开发模式, 所以前期写测试写到吐(还好已经熬过这段时间了)。不过确实在写接口的时候有了这些测试方便了许多。
咦,总感觉跑题了!

进入正题,之前一直想学 正则表达式 ,一直没学(因为任性),趁刚写完一个接口还有时间喘气的时候把它给学了吧!

what is 正则?

正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。

先来几个简单的正则!

  • 假设要在一篇文章中找 ‘hi’ 这个单词。那就直接用正则表达式 hi。 它可以精确匹配这样的字符串:由两个字符组成,前一个字符是h,后一个是i。通常,处理正则表达式的工具会提供一个忽略大小写的选项,如果选中了这个选项,它可以匹配 ‘hi,HI,Hi,hI’ 这四种情况中的任意一种。

  • 但是这时候很多有 ‘hi’ 的单词也会被找到,比方说 ‘high’,‘him’等等,如果要精确查找, 可以用 \bhi\b

\b 是正则表达式规定的一个特殊代码(元字符,metacharacter),能匹配一个单词边界,也就是指单词和空格间的位置。例如, er\b 可以匹配”never” 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。用了 \ber\b后就只能匹配单词 ‘er’

  • \bhi\b.*\bmiao\b : 匹配的字符串是:先是一个单词 hi ,然后是任意个任意字符(但不能是换行),最后是 miao 这个单词。

. 的作用是匹配除 “\n” 之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,使用 [.\n] 的模式。
* 它代表的不是字符,也不是位置,而是数量。它指定 * 前边的内容可以连续重复使用任意次以使整个表达式得到匹配。

元字符

看了上面的几个例子,估计已经大概明白 元字符 是个什么东西了吧。接下来介绍几个基本的元字符

代码说明
.匹配除换行符以外的任意字符
\w匹配字母或数字或下划线或汉字
\s匹配任意的空白符
\d匹配数字
\b匹配单词的开始或结束
^匹配字符串的开始
$匹配字符串的结束

元字符 ^$ 都匹配一个位置,这和 \b 有点类似。^ 匹配用来查找的字符串的开头,$ 匹配结尾。比如一个网站如果要求你填写的QQ号必须为5位到12位数字时,可以使用:^\d{5,12}$

{5,12} 是重复的次数不能少于5次,不能多于12次的意思,否则都不匹配。因为使用了 ^$ ,所以输入的整个字符串都要用来和 \d{5,12} 来匹配,也就是说整个输入必须是5到12个数字,因此如果输入的QQ号能匹配这个正则表达式的话,那就符合要求了。
和忽略大小写的选项类似,有些正则表达式处理工具还有一个处理多行的选项。如果选中了这个选项,^$的意义就变成了匹配行的开始处和结束处。

字符转义

如果想查找元字符本身的话,比如(.*), 就需要使用 \ 来取消这些字符的特殊意义。例如应该使用 \.\*。当然,要查找 \ 本身,得用 \\ .
例如:f10\.moe 匹配 f10.moe,C:\\Windows 匹配 C:\Windows。

限定符

正则表达式中所有的限定符(指定数量的代码,例如*,{5,12}等):

代码/语法说明
*重复零次或更多次
+重复一次或更多次
?重复零次或一次
{n}重复n次
{n,}重复n次或更多次
{n,m}重复n到m次

字符类

要想查找数字,字母或数字,空白是很简单的,因为已经有了对应这些字符集合的元字符,但是如果你想匹配没有预定义元字符的字符集合(比如元音字母 a,e,i,o,u ),应该怎么办?
很简单,你只需要在方括号里列出它们就行了,像 [aeiou] 就匹配任何一个英文元音字母,[.?!]匹配标点符号(.?!)。
我们也可以轻松地指定一个字符范围,像 [0-9] 代表的含意与 \d 就是完全一致的:一位数字;同理 [a-z0-9A-Z_]也完全等同于 \w(如果只考虑英文的话)。


下面是一个更复杂的表达式: \(?0\d{2}[) -]?\d{8}
() 也是元字符,所以在这里需要使用转义。 这个表达式可以匹配几种格式的电话号码,像 (010)88886666 ,或 022-22334455 ,或 02912345678 等。
解析:

  • 转义字符 \( ,它能出现 0 次或 1 次 (?)
  • 然后是一个 0,后面跟着 2 个数字 (\d{2})
  • 然后是 )-空格 中的一个,它出现 1 次或不出现 (?)
  • 最后是 8 个数字 (\d{8})

分枝条件

可是, 刚才那个表达式也能匹配 010)12345678 或 (022-87654321 这样的 “不正确” 的格式。要解决这个问题,我们需要用到 分枝条件 。正则表达式里的 分枝条件 指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用 “|“ 把不同的规则分隔开。

  • 0\d{2}-\d{8}|0\d{3}-\d{7} 可以匹配 010-12345678 或者 0111-1234567 这两种电话号码。

  • \(?0\d{2}\)?[- ]?\d{8}|0\d{2}[- ]?\d{8} 这个表达式匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。

  • \d{5}-\d{4}|\d{5} 这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题:使用分枝条件时,要注意各个条件的 顺序 。如果你把它改成 \d{5}|\d{5}-\d{4} 的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时,将会 从左到右 地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。

分组

上面讲了要重复单个字符时只需在后面加限定符就行,多个字符需要重复时可以用 小括号 来指定 子表达式 (也叫分组)。
例如:

  • (\d{1,3}\.){3}\d{1,3} 是一个简单的IP地址匹配表达式。\d{1,3} 匹配 1 到 3 位的数字,(\d{1,3}\.){3} 匹配三位数字加上一个英文句号(这个整体也就是这个分组)重复 3 次,最后再加上一个一到三位的数字 (\d{1,3})

  • 不幸的是,它也将匹配 256.300.888.999 这种不可能存在的IP地址。如果能使用算术比较的话,或许能简单地解决这个问题,但是正则表达式中并不提供关于数学的任何功能,所以只能使用冗长的分组,选择,字符类来描述一个正确的IP地址:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)

反义

有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义:

代码/语法说明
\W匹配任意不是字母,数字,下划线,汉字的字符
\S匹配任意不是空白符的字符
\D匹配任意非数字的字符
[^x]匹配除了x以外的任意字符
[^aeiou]匹配除了aeiou这几个字母以外的任意字符

正则入门算是差不多了,要了解更多可以点下面链接深入:

http://deerchao.net/tutorials/regex/regex.htm