Bootstrap

正则表达式学习

正则表达式学习


正则简介

正则表达式(简称 regex或者regexp)允许开发人员根据模式匹配字符串、提取子匹配信息,或简单地测试字符串是否符合该模式。

可以用来:

(1)检查一个串中是否含有符合某个规则的子串,并且可以得到这个子串;

(2)根据匹配规则对字符串进行灵活的替换操作

一、正则基础
  • 单词全写:匹配单词

    of 匹配含有of单词的内容
    
  • .符号 : 匹配任意字符,除了换行符

  • ^ 符号:字符串开始的地方匹配,不匹配任何字符

  • $ 符号:字符串结束的地方匹配,不匹配任何字符

  • \b :匹配一个单词边界,也就是单词和空格之间的位置,不匹配任何字符

  • [字符列表]:匹配字符集

    [bdf]eer 匹配beer deer feer
    [ab5@] 匹配 "a""b""5""@"
    
  • [^字符列表] : 除字符集

    be[^ou]r 匹配be...r形式的内容中间不包含o,u的内容
    [^abc] 匹配 "a","b","c" 之外的任意一个字符
    [^A-F0-3] 匹配 "A"~"F","0"~"3" 之外的任意一个字符
    
  • [起点字符-终点字符] :字母范围

    [g-k] 匹配g-k任意字符
    [0-9] 匹配0-9任意数字,等价于 /\d/
    [f-k] 匹配 "f"~"k" 之间的任意一个字母
    
  • 重复: + * ?{m,n}]

    +号  :表示至少重复/出现一次,用于要标识的字符后面,相当于 {1,},比如:"a+b"可以匹配 "ab","aab","aaab".
    \*号 :表示不出现或者出现一次或者并排出现多次,相当于 {0,},比如:"\^*b"可以匹配 "b","^^^b"
    ?号  :表示可选,即可有可无,出现0次或者1次,相当于 {0,1},比如:"a[cd]?"可以匹配 "a","ac","ad"
    {n}  :表示确切出现的次数,即准确次数匹配,比如:"\w{2}" 相当于 "\w\w""a{5}" 相当于 "aaaaa"
    {m,} :表示至少出现m次,比如:"\w\d{2,}"可以匹配 "a12","_456","M12344"
    {m,n}:表示出现次数在m和n之间【闭区间】,比如:"ba{1,3}"可以匹配 "ba""baa"或"baaa
    
  • ()号:分组,或者捕获分组

    (haa)  表示对文本中的 haa 构造分组,为了给表达式分组,我们需要将文本包裹在 ()(d)(\w+) "\w+" 将匹配第一个 "d" 之后的所有字符 "xxxdxxxd"
    (d)(\w+)(d) "\w+" 将匹配第一个 "d" 和最后一个 "d" 之间的所有字符 "xxxdxxx"。虽然 "\w+" 也能够匹配上最后一个 "d",但是为了使整个表达式匹配成功,"\w+" 可以 "让出" 它本来能够匹配的最后一个 "d"
    
    (d)(\w+?) "\w+?" 将尽可能少的匹配第一个 "d" 之后的字符,结果是:"\w+?" 只匹配了一个 "x"
    (d)(\w+?)(d) 为了让整个表达式匹配成功,"\w+?" 不得不匹配 "xxx" 才可以让后边的 "d" 匹配,从而使整个表达式匹配成功。因此,结果是:"\w+?" 匹配 "xxx"
    
  • (?: ):非捕获分组,可以对表达式进行分组,并确保它不被引用捕获,不会存储,优化性能

    例如,如果我们想匹配一个日期格式 2019-11-10 并分别获取年、月、日,我们可以使用捕获分组来实现
    (\d{4})-(\d{2})-(\d{2})
    这将创建三个捕获分组,分别保存年、月、日的匹配结果。
    但如果我们不需要单独引用这些分组中的数据,我们可以使用非捕获分组来改写表达式:
    (?:\d{4})-(?:\d{2})-(?:\d{2})
    这样,正则表达式仍然可以匹配相同的日期格式,但不会保存匹配的年、月、日到内存中。
    
  • ()-\n:引用组

    反向引用 \1, \2...
    举例 1:表达式 "('|")(.*?)(\1)" 在匹配 " 'Hello', "World" " 时,匹配结果是:成功;
    匹配到的内容是:" 'Hello' "。再次匹配下一个时,可以匹配到 " "World" "。
    
    举例 2:表达式 "(\w)\1{4,}" 在匹配 "aa bbbb abcdefg ccccc 111121111 
    999999999" 时,匹配结果是:成功;匹配到的内容是 "ccccc"。再次匹配下一个时,将得到
    999999999。这个表达式要求 "\w" 范围的字符至少重复 5 次,注意与 "\w{5,}" 之间的区别
    
    举例3:
    单词 ha 和 haa 分组如下:
    ha-ha,haa-haa
    第一组用 \1 来避免重复书写。这里的 1 表示分组的顺序。请在表达式的末尾键入 \2 以引用第二组:
    (ha)-\1,(haa)-\2
    
  • |竖线:竖线允许一个表达式包含多个不同的分支。所有分支用 | 分隔,左右两边表达式之间 “或” 关系,匹配左边或者右边。

    下面的表达式同时匹配 cat 和 rat。请在末尾添加另一个 |,并输入 dog 以匹配所有单词。
    cat rat dog
    正则:
    (c|r)at|dog
    
  • \转义符:当正则使用 { } [ ] / \ + * . $^ | ? 这些特殊字符 ,为了匹配这些特殊字符本身,我们需要通过 \ 将它们转义。

    \r 代表回车
    \n 代表换行符
    \t 代表制表符
    \\ 代表 "\" 本身
    \^ 匹配 ^ 符号本身
    \$ 匹配 $ 符号本身
    \* 匹配 * 符号本身
    \. 匹配 .$ 符号本身
    \[\] 匹配 [] 符号本身
    ...
    
    例如,要匹配文本中的 . 和 *,我们需要在它们前面添加一个 \。
    正则:
    (\*|\.)
    
  • ^插入符: 匹配字符串的开始

    我们用 [0-9] 查找数字,若仅查找行首的数字,请在表达式前面加上 ^
    Basic Omellette Recipe
    1. 3 eggs, beaten
    2. 1 tsp sunflower oil
    3. 1 tsp butter
    正则:
    ^[0-9]
    
  • $美元符号: 匹配字符串的结束

    例如在 html 的后面添加 $,来查找仅在行末出现的 html
    https://domain.com/what-is-html.html
    https://otherdomain.com/html-elements
    https://website.com/html5-features.html
    正则:
    html$
    
  • 单词字符 \w: 字母、数字和下划线

  • 非单词字符 \W

  • 数字字符 \d

  • 非数字字符 \D

  • 空白符 \s

  • 非空白符 \S

  • \B 匹配非单词边界,即左右两边都是 “\w” 范围或者左右两边都不是 “\w” 范围时的字符缝隙

二、正则提升
  • 零宽断言

    • 正向先行断言/正向预搜索: (?=)

      例如,我们要匹配文本中的小时值。为了只匹配后面有 PM 的数值,我们需要在表达式后面使用正向先行断言 (?=),并在括号内的 = 后面添加 PM。
      文本:Date: 4 Aug 3PM
      正则:\d+(?=PM)
      结果:3
      
    • 负向先行断言/正向预搜索: (?!)

      例如,我们要在文本中匹配除小时值以外的数字。我们需要在表达式后面使用负向先行断言 (?!),并在括号内的 ! 后面添加 PM,从而只匹配没有 PM 的数值。
      文本:Date: 4 Aug 3PM
      正则:\d+(?!PM)
      结果:4
      
    • 正向后行断言/反向预搜索: (?<=)

      例如,我们要匹配文本中的金额数。为了只匹配前面带有 $ 的数字。我们要在表达式前面使用正向后行断言 (?<=),并在括号内的 = 后面添加 \$。
      文本:Product Code: 1064 Price: $5
      正则:(?<=\$)\d+
      结果:5
      
    • 负向后行断言/反向预搜索: (?<!)

      例如,我们要在文本中匹配除价格外的数字。为了只匹配前面没有 $ 的数字,我们要在表达式前用负向后行断言 (?<!),并在括号内的 ! 后面添加 \$。
      文本:Product Code: 1064 Price: $5
      正则:/(?<!\$)\d+/g
      结果:1064
      
  • 标志/表达式属性:标志改变表达式的输出。这就是标志也称为 修饰符 的原因。标志决定表达式是否将文本视作单独的行处理,是否区分大小写,或者是否查找所有匹配项。

    • 全局标志 : /…/g:全局标志使表达式选中所有匹配项,如果不启用全局标志,那么表达式只会匹配第一个匹配项。
    • 多行标志 /…/gm:正则表达式将所有文本视作一行。但如果我们使用了多行标志,它就会单独处理每一行。
    • 忽略大小写标志/…/gmi:表达式不再大小写敏感,可以启用不区分大小写标志
  • 贪婪匹配.*:正则表达式默认执行贪婪匹配。这意味着匹配内容会尽可能长。

    它匹配任何以 r 结尾的字符串,以及前面带有该字符串的文本,但它不会在第一个 r 处停止匹配。
    文本:ber beer beeer beeeer
    正则:/.*r/
    
  • 懒惰匹配.*?:与贪婪匹配不同,懒惰匹配在第一次匹配时停止。

    在 * 之后添加 ?,将查找以 r 结尾且前面带有任意字符的第一个匹配项。这意味着本次匹配将会在第一个字母 r 处停止。
    文本:ber beer beeer beeeer
    正则:/.*?r/
    
三、使用案例
  • 示例:^.{m,n}$

    匹配固定长度内容:^.{n}$,匹配任意开头但是长度n的内容
    匹配最小长度内容:^.{m,}$,匹配任意开头但是长度不低于m的内容
    匹配区间长度内容:^.{m,n}$,匹配任意开头但是长度在[m,n]之间的内容
    
  • 示例:.*匹配

    在正则表达式的末尾添加 .* 来匹配以 how to write 开头的表达式,并匹配后面的所有内容。
    正则1:^how to write
    正则2:how to write.*
    
    在两个 .* 之间写上我们要查找的字段,以匹配包含该字段的所有的内容。例如匹配包含buy的内容
    正则:.*buy.*
    
    在.*\.和$之间加入想要作为结尾的字段,可以匹配以.XX格式结尾的内容,例如匹配.html文件
    正则:.*\.html$
    
  • 匹配http、https

    匹配http或者https
    正则1:^http 或者 ^(http|https)【仅作为开头】
    正则2:http.*【不限于开头】
    
    匹配非https即只要http
    正则:http[^s].*
    
    URL:^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
    
  • 域名

    域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?
    
  • 邮箱Email

    Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
    
  • 手机号

    手机号码:^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$
    
    电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"等格式):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$
    
    国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
    
  • 身份证

    身份证号(15位、18位数字),最后一位是校验位,可能为数字或字符X:(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)
    
  • 密码

    强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$
    强密码(必须包含大小写字母和数字的组合,可以使用特殊字符,长度8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
    
  • QQ号

    腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
    
  • 邮政编码

    中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
    
  • Ipv4地址

    IPv4地址:((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}
    
  • 其他

    空白行的正则表达式:\n\s*\r (可以用来删除空白行)
    HTML标记的正则表达式:<(\S*?)[^>]*>.*?|<.*? /> 
    首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等))
    
四、附录
;