# 正则表达式必知必会

# 1. 第 1 章 正则表达式入门

用途:

  • 解决特定的问题而发明的一种工具

如何使用:

  • 搜索
  • 替换

什么是正则:

  • 正则表达式,regular expression,RegEex,regex,模式
  • 正则表达式是一些用来匹配和处理文本的字符串
  • 正则表达式语言用来构造正则表达式,正则表达式用来完成搜索和替换操作。

# 2. 第 2 章 匹配单个字符

匹配普通文本:

  • Ben

匹配多个结果:

  • 正则表达式引擎默认返回第一个匹配结果
  • JS 中,使用 g 来返回所有匹配结果

字母的大小写:

  • 正则表达式是区分大小写的
  • JS 中,使用 i 忽略大小写

匹配任意单个字符:

  • . 点符号,特殊字符,表示任意单个字符
  • \. 匹配点符号本身,转义

元字符:

  • 有特殊含义的字符
  • . , \

# 3. 第 3 章 匹配一组字符

匹配多个字符中的一个:

  • [abc]
  • 元字符 [ , ] 用来定义一个字符集合,必须匹配集合中的字符之一

字符区间:

  • A-Z: 从大写字符 A 到大写字符 Z
  • a-z: 从小写字符 a 到小写字符 z
  • A-z: 这个区间包含 [ ,^ 等字符

排除:

  • [^xyz] 排除字符集合中的所有字符

注意:

  • - 只有在 [a-z] 中才是元字符,在其他地方就是普通字符
  • [\w.]: \w 是元字符,. 是普通字符
  • [\/]: 斜线 /[ ] 中可以不用转义,但有些正则引擎要求转义

# 4. 第 4 章 使用元字符

转义:

  • 元字符有特殊含义,无法代表自身
  • 通过 \ 元字符来对元字符进行转义

空白字符:

元字符 说明
\b 回退(Backspace 键)
\f 换页符
\n 换行符
\r 回车符
\t 制表符(Tab 键)
\v 垂直制表符

文本行结束标记:

  • \r\n: windows 系统
  • \n: Unix 系统

普通字符转义为元字符:

  • \ 对普通字符使用,可以将普通字符转义为元字符

匹配数字:

  • \d: 数字,[0-9]
  • \D: 非数字,[^0-9]

匹配字母数字下划线:

  • \w: 字母数字下划线, [a-zA-Z0-9_]
  • \W: 非字母数字下划线, [^a-zA-Z0-9_]

匹配空白字符:

  • \s: 空白字符, [\f\n\r\t\v]
  • \S: 非空白字符, [^\f\n\r\t\v]

# 5. 第 5 章 重复匹配

量词:

  • *: 匹配 0 个或多个
  • +: 匹配 1 个或多个
  • ?: 匹配 0 个或 1 个

区间范围:

  • {m}: 匹配 m 个
  • {m, n}: 匹配至少 m 个,最多 n 个
  • {m,}: 匹配至少 m 个

贪婪型量词:

  • * / + / {m,}
  • 没有上限,尽可能多的匹配

懒惰型量词:

  • *? / +? / {m,}?
  • 尽可能少的匹配,碰到第一个匹配就停止

# 6. 第 6 章 位置匹配

单词边界:

  • \b: 匹配一个单词的开头或结尾,匹配一个位置,一边是单词(\w) 一边是其他内容(\W)
  • \bcat\b: 匹配完整的单词
  • \bcat: 匹配以 cat 打头的单词
  • cat\b: 匹配以 cat 结尾的单词

字符串边界:

  • ^a: 匹配以 a 打头的
  • a$: 匹配以 a 结尾的
  • 多行模式:^,& 会作用到每一行

# 7. 第 7 章 使用子表达式

子表达式:

  • 元字符: ( , )

  • 示例:

    (19|20)\d{2}
    
      |, 是或操作符, 从左到右匹配,匹配第一个就停止
    

子表达式嵌套:

  • 示例:匹配 IP 地址

    分析:
      1. 一位数: 
          
          \d
    
      2. 两位数:
    
          \d{2}
    
      3. 三位数
    
          1 开头:  1\d{2}
          2 开头:
              第 2 位是 0 ~ 4: 2[0-4]\d
              第 2 被是 5:     25[0-5]
    
    综上:
    
      ( ( (25[0-5]) | (2[0-4]\d) | (1\d{2}) | (\d{2}) | (\d) ) \. ){3} ( (25[0-5]) | (2[0-4]\d) | (1\d{2}) | (\d{2}) | (\d) )
    
      (((25[0-5])|(2[0-4]\d)|(1\d{2})|(\d{2})|(\d))\.){3}((25[0-5])|(2[0-4]\d)|(1\d{2})|(\d{2})|(\d))
    

# 8. 第 8 章 反向引用

反向引用匹配:

  • 通过 \n 引用第 n 个分组(子表达式)匹配的结果

  • 在 JS 中,使用 \n 标识反向引用,在替换中用 $n 标识

  • 示例:匹配连续单词

    `
    this is a block of of text,
    several words here are are
    repeated, and and they should not be;
    `
    .match(
      /[ ](\w+)[ ]\1/g
    )
    
    /* =>
    
    (3) [' of of', ' are are', ' and and']
    
    */
    
    
    /* 
    分析:
      [ ](\w+)[ ]\1
    
        [ ](\w+)[ ]\w+
        两个 \w+ 要求内容一样
    */
    
  • 示例:匹配 HTML 中 <hn> 标签:

    `
    <body>
      <h1>xxx yy zz</h1>
      xxx yy zz
      <h2>xxx yy zz</h2>
      xxx yy zz
      <h5>xxx yy zz</h2>
      xxx yy zz
    </body>
    `
    .match(
      /<h([1-5])>.*?<\/h\1>/gi
    )
    
    /* =>
    
    (2) ['<h1>xxx yy zz</h1>', '<h2>xxx yy zz</h2>']
    
    */
    

替换操作:

  • 跨模式使用反向引用

  • 示例:将邮箱地址替换为可点击的:

    `
      hello, forward@qq.com is my email address.
    `
    .replace(
      /(\w+[\w\.]*@[\w\.]+\.\w+)/,
      '<a href="mailto:$1">$1</a>'
    )
    
    /* =>
    
    '\n  hello, <a href="mailto:forward@qq.com">forward@qq.com</a> is my email address.\n'
    
    */
    

# 9. 第 9 章 环视

说明:

  • 更精细地控制返回的文本

肯定式向前查找:

  • 语法: (?=内容)

  • 说明:既匹配前面的内容,也匹配后面的内容,返回前面的内容

  • 示例:

    `
      http://www.a.com
      https://www.b.com
      ftp://www.c.com
    `
    .match(
      /\w+(?=:)/g
    )
    
    /* =>
    
    (3) ['http', 'https', 'ftp']
    
    */
    

否定式向前查找:

  • 语法: (?!内容)

  • 说明:匹配前面的内容,但不匹配后面的内容,返回前面的内容

  • 示例:

    `
      12.34
    `
    .match(
      /\d{2}(?!\.\d{2})/g
    )
    
    /* =>
    
    ['34']
    
    */
    

# 10. 第 10 章 嵌入式条件

反向引用 条件:

  • 语法:

    • (?(1)内容): 如果第 1 个子表达式存在,则执行内容
    • (?(1)内容1 | 内容2): 如果第 1 个子表达式存在,则执行内容1,否则执行内容2

注意:

  • (?(1)xx) 语法在浏览器端报错 Invalid regular expression

# 11. 第 11 章 常见正则

# 11.1. 国内固定电话号码

规则:

  1. 第 1 位,0 : 表示长途冠码
  2. 第 2 ~ 3 位: 区号
  3. 最后是 7 位或 8 位的电话号码,首位不为 1
  4. 常见写法:
    • (012)3456 7890
    • (012)34567890
    • 012-34567890

分析:

  • 前三位,区号:

    • (012): \(0\d{1,2}\)
    • 012-: 0\d{1,2}-
  • 号码

    • 3456 7890: \d{2,4}\s?\d{3,4}

正则:

  • (\(0\d{1,2}\)|0\d{1,2}-)\d{2,4}\s?\d{3,4}

测试:

`
    * (012)3456 7890
    * (012)34567890
    * 012-34567890
`
.match(
  /(\(0\d{1,2}\)|0\d{1,2}-)\d{2,4}\s?\d{3,4}/g
)

/* =>

(3) ['(012)3456 7890', '(012)34567890', '012-34567890']

*/

# 11.2. 北美电话号码

规则:

  1. 3位区号 + 7位号码

  2. 7位号码: 3位局号 + 4位线路号

  3. 区号 和 局号 不能为 0/1

  4. 常见写法:

    • 248-555-1234
    • (313) 555-1234
    • (810)555-1234
    • 734.555.9999

分析:

  • 前三位,区号

    • 248-: \d{3}-
    • (810): \(\d{3}\)\s
    • (313): \(\d{3}\)
    • 734.: \d{3}\.
    • 综上: [(]?\d{3}[-).]\s?
  • 号码

    • 555-1234: \d{3}[-]\d{4}
    • 555.9999: \d{3}[.]\d{4}
    • 综上: \d{3}[-.]\d{4}

正则:

  • [(]?\d{3}[-).]\s?\d{3}[-.]\d{4}

测试:

`
    * 248-555-1234
    * (313) 555-1234
    * (810)555-1234
    * 734.555.9999
`
.match(
  /[(]?\d{3}[-).]\s?\d{3}[-.]\d{4}/g
)

/* =>

(4) ['248-555-1234', '(313) 555-1234', '(810)555-1234', '734.555.9999']

*/

# 11.3. 美国 ZIP 编码

正则:

  • \d{5}(-\d{4})?

# 11.4. IP 地址

参见 第 7 章

# 11.5. URL

规则:

  1. 协议: http:// https:// ftp://
  2. 用户名密码: root:123@
  3. 主机名: www.z.com
  4. 端口号: :12345
  5. 路径: /abc/index.html
  6. 查询字符串:?a=b

分析:

  • 协议: ((https?)|(ftp)):\/\/
  • 用户密码: \w*:\w*@
  • 主机名:[-\w]+([.][-\w]+)*
  • 端口号::\d{1,5}
  • 路径:(\/[\w_.]+)+\/?
  • 查询字符串:\?\S+

正则:

  • ((https?)|(ftp)):\/\/(\w*:\w*@)?[-\w]+([.][-\w]+)*(:\d{1,5})?((\/[\w_.]+)+\/?)?(\?\S+)?

测试:

`
  http://localhost:8080
  http://www.abc.com
  http://www.abc.com/blog
  https://www.abc.com:80/blog/index.html
  https://root:123456@www.abc.com:80/blog/index.html?a=1&b=2
`
.match(
  /((https?)|(ftp)):\/\/(\w*:\w*@)?[-\w]+([.][-\w]+)*(:\d{1,5})?((\/[\w_.]+)+\/?)?(\?\S+)?/gi
)

/* =>

(5) ['http://localhost:8080', 'http://www.abc.com', 'http://www.abc.com/blog', 'https://www.abc.com:80/blog/index.html', 'https://root:123456@www.abc.com:80/blog/index.html?a=1&b=2']

*/

# 11.6. 电子邮件地址

正则:

  • (\w+\.)*\w+@(\w+\.)*[a-zA-Z]+

# 11.7. HTML 注释

正则:

  • <!--.*?-->

# 11.8. JS 单行注释

正则:

  • \/\/.*

# 12. 附录

# 12.1. JavaScript

String.prototype 的方法:

  • match:
  • replace:
  • search:
  • split:

RegExp.prototype 的方法:

  • exec:
  • test:

标志:

  • g: 全局搜索
  • i: 忽略大小写
  • m: 多行
  • x: 忽略正则表达式中的空白字符

反向引用:

  • $` : $ + 反引号,匹配字符串 前面的所有内容
  • $' : $ + 单引号,匹配字符串 后面的所有内容
  • $+ : $ + 加号, 最后一个匹配的子表达式
  • $& : $ + &, 返回所匹配到的所有内容

示例:

`aaa-bbb`.replace( /(-)/g, '$`' ); // 'aaaaaabbb'

`aaa-bbb`.replace( /(-)/g, '$\'' ); // 'aaabbbbbb'

`aaa-bbb.ccc`.replace( /([-.])/g, '($&)' ); // 'aaa(-)bbb(.)ccc'

# 12.2. 速查表

基本的元字符:

元字符 说明
. 匹配任意单个字符
| 逻辑或操作
[ ] 匹配字符集合中的一个字符
[^ ] 排除该字符集合
[ - ] 定义一个范围
\ 对下一个字符转义

量词元字符:

元字符 说明
* 匹配前一个字符(子表达式)的零次或多次重复
*? *的懒惰型版本
+ 匹配前一个字符(子表达式)的 1 次或多次重复
+? +的懒惰型版本
? 匹配前一个字符(子表达式)的 0 次或 1 次重复
{n} 匹配前一个字符(子表达式)的 n 次重复
{m,n} 匹配前一个字符(子表达式)的 [m, n] 次重复
{n,} 匹配前一个字符(子表达式)的 [n, ∞) 次重复
{n,}? {n,}的懒惰型版本

位置元字符:

元字符 说明
^ 匹配字符串的开头
$ 匹配字符串的结尾
\b 匹配单词边界(开头和结尾)
\B \b的反义

特殊元字符:

元字符 说明
\d 匹配任意数字字符,等价于 [0-9]
\D \d的反义
\w 匹配任意 数字、字母、下划线,等价于 [0-9a-zA-Z_]
\W \w的反义
\s 匹配任意空白字符,等价于 [ \t\v\r\n\f](里面有个空格)
\S \s的反义
\t 制表符
\v 垂直制表符
\r 回车符
\n 换行符
\f 换页符
[\b] 退格字符
\c 匹配一个控制字符
\x 匹配一个十六进制数字
\0 匹配一个八进制数字

反向引用与环视:

元字符 说明
() 定义一个子表达式
\1 匹配第 1 个子表达式,\2匹配第二个子表达式,以此类推
?= 肯定式向前查看
?! 否定式向前查看
本章目录