• 正则表达式从入门到高级


    序言

    对于正则,许多程序员都觉得它很繁琐,找不到头绪。但其实只要明白了基础语法,正则其实是非常简单的。学习正则表达式一定要躬行实践,自己动手来测试的自己表达式,这将大大有益对于正则表达式的掌握。在正文开始前,先给大家推荐一个好用的正则在线测试工具,本文后面将会使用它来对我们编写的正则表达式做测试:https://c.runoob.com/front-end/854/

    基础语法

    正则表达式的基本形式:/pattern/flags 。其中 pattern 是匹配规则,flage 被称为修饰符。我们先来看一个简单的示例:

    正则:/you/g
    文本:If you shed tears when you miss the sun, you also miss the stars
    匹配结果:
    you
    you
    you

    提示:在每一个示例下面,可以通过上面提供的在线测试工具来自己测试一下,加深理解。在线测试工具的结果:

    在上面的示例中,/g 被称为全局匹配,是一个常用修饰符,表示匹配字符串中的所有元素,即匹配了3个 you

    修饰符

    修饰符用于标记正则表达式的额外策略,下面四个是常用的修饰符:

    字符 描述
    g 全局匹配
    i 忽略大小写
    m 多行模式
    s 该模式下,.会匹配换行符\n

    g 在所有的表达式中基本都需要携带,i 望文知义。 m 和 s 我们会在后文中逐渐的认识到,现在不必纠结他们。

    元字符

    元字符这个概念比较难以被理解,通常会直接劝退一批想学正则表达式的人。其实元字符说白了,就是规定一个普通字符具备特殊含义,用来匹配符合这个特殊含义的字符。我们先列举出常用的一些元字符,逐项来看他们的所具备的特殊含义。

    选择与分支

    字符 描述
    sea|sky 匹配 sea 或者 sky,可以匹配若干个,如 sea|sky|stars
    [abc] 匹配 a 和 b 和 c
    [^abc] 匹配除了 a 和 b 和 c 之外的字符
    [a-z] 匹配 a 到 c 之间的所有小写字符,也可以使用[0-9]匹配数字范围
    [a-z] 匹配除了 a 到 c 之间的所有小写字符,同理,也可以匹配数字范围

    以上五个选择分支的匹配规则是很常用的匹配规则。通常,sea|sky 这种匹配方式会被 () 括起来:

    () 也是一种元字符,通常用来把一组匹配规则括起来,表示一个分组。

    基础元字符

    字符 描述
    . 匹配任意字符,不包括换行符\n和\r,如果需要匹配 \n和\r ,可以使用修饰符:s
    \d 匹配一个数字,相当于 [0-9]
    \D 匹配非数字,相当于 [^0-9]
    \s 匹配任意空白字符,相当于 [\t\n\r\f\v]
    \S 匹配非空白字符,相当于 [^\t\n\r\f\v]
    \w 匹配数字、字母、下划线中任意一个字符,相当于 [a-zA-Z0-9_]
    \W 匹配非数字、字母、下划线中的任意字符,相当于 [^a-zA-Z0-9_]

    \ 也是一个基础元字符,用来将元字符转换为普通字符,类似于编程语言中的转义。如真的要匹配 . 这个字符,应该使用 \. ,否则 . 将会被识别为匹配任意字符。正则表达式中需要的转义字符:* . ? + $ ^ [ ] ( ) { } | \

    边界元字符

    还有一些基础元字符:边界元字符。其不占用字符位置,只是表达一个边界:

    字符 描述
    \b 匹配位于每个单词的开始或结束位置
    \B 匹配不是单词开头和结束的位置,即每个单词的中间位置
    ^ 匹配开始位置,多行模式下匹配每一行的开始
    $ 匹配结束位置,多行模式下匹配每一行的结束

    \b\B 比较容易理解,\b 可以粗略的理解就是匹配单词之间的空格,但是匹配结果不会携带这个空格。\B 则是和 \b 相反:

    ^& 匹配有一个很重要的概念:行。他们表示了一行的开始和结束位置。我们来看一个示例:

    可以看到,加入了 ^ 后,an 的匹配只会从行首开始匹配,我们这里加入 i 修饰符,表示不区分大小写的匹配。& 同理:

    为什么说行是 ^& 的重要概念呢,我们来看一组示例。ok& 可以匹配以 ok 为结束的字符:

    这显然符合我们的预期,但是当我们在加入一行文本,匹配结果就会出现意外:

    按照道理说,应该能匹配到两个 ok 字符,但是这里只匹配到了最后一行,如果需要匹配多行数据,则需要加入一个修饰符:m (多行模式)。让我们看一下加入多行模式后的匹配结果:

    这样就符合了我们的预期情况。

    重复匹配

    字符 描述
    * 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。
    + 匹配前面的子表达式一次或多次。例如,zo+ 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
    ? 匹配前面的子表达式零次或一次。例如,do(es)? 可以匹配 "do" 或 "does" 。? 等价于 {0,1}。
    {n} n 是一个非负整数。匹配确定的 n 次。例如,o{2} 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
    {n,} n 是一个非负整数。至少匹配 n 次。例如,o{2,} 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。o{1,} 等价于 o+。o{0,} 则等价于 o*。
    {n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,o{1,3} 将匹配 "fooooood" 中的前三个 o。o{0,1} 等价于 'o?'。请注意在逗号和两个数之间不能有空格。

    在该匹配的模式下,还有一个特殊的元字符:。被称为非贪婪模式。注意,该 和上文的匹配零次或一次完全不同。非贪婪模式的元字符 ? 只能跟在上述六个的重复匹配后面。例如,我们想要匹配出一段文本中的以 http 或者 https 开头的图片地址:

    示例文本中存在两个 .png 的图片,我们使用 (http:https) 来匹配 http 或者 https 开头,然后使用 . 来匹配所有字符,再加上 + ,表示一次或多次匹配,最后使用 (.png) 表示匹配 .png 结束。但这样的结果就是当我们遇到第一个 .png 时,.+ 也会匹配到 .png,所以就导致了获取了错误的匹配结果。遇到这种情况,我们就要使用非贪婪模式,在 + 后面加上 ? :

    可以看到,此时获取了我们想要的结果。非贪婪模式下,会尽可能少的匹配字符串

    到此,我们已经掌握了正则表达式的基础,可以找一些实际的业务需求来加深理解。比如说检测邮箱地址是否合法:

    \w 会匹配所有数字、字母下划线, + 表示至少需要匹配到一个字符,我们要求它需要到 @ 时停下,所以加上 ? 非贪婪模式。这样就可以成功匹配到 tyyn1022@ 。继续检测后面的是否符合要求,同样使用 \w+? 匹配域名名称,\. 表示匹配文本 . ,最后加上 (com|net|top|org),即要求顶级域名必须是 com、net、top、org。这样就匹配到了剩余的部分:163.com

    零宽断言

    零宽断言是正则表达式的高级用法,它一种特殊的元字符。实际作用就如同它的名字:零宽与断言。简而言之,就是匹配某个字符的前后,却又不想匹配到这个字符本身(零宽的意思)。零宽断言分为四种:

    字符 描述
    (?=pattern) 正向先行断言。例如,foo(?=bar) 会匹配 foobar 中的 foo。
    (?!pattern) 反向先行断言。例如,foo(?!bar) 会匹配 foobaz 中的 foo,但不会匹配 foobar 中的 foo。
    (?<=pattern) 正向后行断言。例如,(?<=foo)bar 会匹配 foobar 中的 bar,但不会匹配 bazbar 中的 bar,因为它前面不是 foo。
    (? 反向后行断言。例如,(?

    我们来举一个实际的例子,我们需要从一段富文本文本中匹配所有以 http:// 或者 https:// 开头,以 .png 或者 .jpg 结尾的图片地址,但是要求不能把 http:// 和 https:// 匹配进去

    /((?<=http://)|(?<=https://)).+?(.png|.jpg)/ig

    该正则表达式即可达到我们想要的效果:

    在该表达式中分为三段:

    1. ((?<=http://)|(?<=https://)),正向后行断言,表示匹配以 http:// 或者 https:// 开头的字符
    2. .+?,匹配除了换行符 \n 和 \r 之外的所有字符至少一次,且是非贪婪模式,为什么这里使用贪婪模式,可以自己动手试一下
    3. (.png|.jpg) 表示以 .png 或者 .jpg 结尾
  • 相关阅读:
    mac上输入 insert和replace的快捷键切换
    提升 Python 执行速度:Codon、C/C++、Rust、Numba(JIT)、Taichi、Nuitka、MatxScript
    vuedraggable遇到的问题
    【LeetCode】两数之和
    Error: max no of 200 conversations exceeded pyrfc
    一行代码解决WINFORM因为系统放大导致的布局混乱
    2022年武汉名品认定条件以及申报奖励补贴标准汇总
    AMCL代码详解(七)amcl中的kd-Tree
    2021 CCPC 威海 A J G D(树,计算几何,组合数,字符串哈希)
    TypeScript_基本类型
  • 原文地址:https://www.cnblogs.com/oldme/p/17664001.html