导读 | 余晟:我是怎么学习和使用正则的?

你好,我是余晟。受伟忠的邀请,今天我来和你聊聊我是怎么学习和使用正则的。

刚工作那会儿,因为密集用到正则表达式,所以我花了不少时间去钻研正则相关的问题,因此获得了机会,翻译了《精通正则表达式》(第三版),后来又写了一本书《正则指引》。到如今,许多年过去了,这些东西还历历在目,我也很乐意拿出来和你分享一下,希望在学习正则的道路上,能给你一些启发。

我经常在网上看到,许多⼈抱怨正则表达式“难学”,我知道,它确实不好学。但同时,我也去看过大家的抱怨,发现和我之前的做法⼀样:用到什么功能,就去网上搜⼀个例⼦来改改,能跑通就满意。至于这例子到底如何构成的,自己是不是都懂了,其实心里没底,能大概看懂五六分,就已经很满足了。

这样浮光掠影的使用方法或许能解决眼前的问题,但⼀定不算“学会”。它有点像打井,每次挖到⼀点水就满足了,根本不管有没有持续性,也不关心挖没挖到含水层。结果就是,每次要喝水的时候,你都得重新打⼀眼井。

那么对于正则表达式,我们有没有可能打出一口“永不干涸”的深井呢?当然有,那就是⼀次性多投入点时间,由表及里,由术及道。一旦掌握了方法,之后就简单很多了

按照我的经验,如果每天花一刻钟或者半小时,坚持个把礼拜,通常都能登堂入室,达到“不会忘”的境界。不要以为这时间很多,我知道有些人很喜欢找“正则表达式五分钟入门”,其实每次都没有入门,日积月累,反而浪费了几十甚至上百个五分钟。

那多投入时间很好理解,但是什么叫掌握方法呢?用我的话说,就是摆脱了字符的限制,深入到概念思维的层面。不要盯着那些鬼画桃符⼀般的字符和表示法皱眉,要摆脱桃符,把真正的“鬼”给认出来——虽然它们不那么容易看见。 也正因为这样,我们才需要⼀次性多投入点时间。

那最终怎样才算“入门”了呢?按照我的经验,就是通过学习掌握方法,后来无论用正则表达式解决什么问题,都能自发遵循下面的流程去走,甚至能达到不需要这个流程,也能做到解决问题,那基本上就算入门了。

第⼀步,做分解。拿到一个问题后,我们要先思考:这个问题可以分为几个子问题?每个子问题是否独立?我们拿最常见的电子邮件地址匹配来说。从文本结构来看,它可以分为“username + @ + domain name”这三个独立的部分。怎么画呢?我们可以先画出逻辑结构图。通过这个过程来厘清思路。当然,这是软件⼯程最基本的思路,相信你做起来应该问题不大。

第⼆步,分析各个子问题。某个位置上可能有多个字符?那就用字符组。某个位置上可能有多个字符串?那就用多选结构。出现的次数不确定?那就用量词。对出现的位置有要求?那就用锚点锁定位置…… 某种程度上,这就像武术里的见招拆招,每个问题都有对应的解法,只要熟练掌握了,知道什么时候用字符组,什么时候用多选结构,什么时候用量词,什么时候用锚点,就很容易搭建起完整的概念模型。

第三步,套皮。 你大概注意到了,到现在,我们还没有谈论正则表达式的典型标志,比如方括号、星号、花括号。要知道,这些典型标志无非只是一些符号而已,真正重要的是字符组、多选结构、量词等等这些概念。一旦你的概念模型清楚了,写出正则表达式就非常简单了,无非是查阅语法手册,把之前得到的概念模型按照对应语言或工具的约定写下来而已。

许多人觉得正则表达式难懂,总是纠缠于“这里为什么要多一个星号?那里为什么是方括号而不是花括号?”,原因恰恰在于对概念模型不清楚。虽然各种语言或工具对正则表达式的支持大同小异,但细微差别仍然不可忽视。不过只要你心怀正念,洞若观火,这些差异其实并不是大问题。

第四步,调试。很多人都说,正则表达式的麻烦之处在于它像个黑箱子,很难调试,迄今为止仍然没有特别好用的⼯具,所以我们没法⼀步步跟进去看匹配的具体过程,只能笼统地知道“匹配了”或者“没匹配”。

那到底怎么调试呢?我的经验是,复杂⼀点的正则表达式不能⼀次写对,这是很正常的。与其纠结“这个正则表达式看起来这么复杂,此处到底要用星号*还是加号+,不如先搞清楚,星号( * )或加号( + )限定的到底是正则表达式中的哪一部分,对应要匹配文本中的哪一部分。这两个问题搞清楚了,整个问题就迎刃而解了。

另外,还有⼀点统摄全局的经验想和你说一下, 那就是学会了正则表达式之后,务必要保持克制 。写正则表达式很容易上瘾,毕竟它的功能那么强⼤,处理速度那么快,⼜像天书符咒那样充满了“神秘”色彩。于是,“写⼀条其他⼈看不懂的正则表达式,⼀次性解决所有问题”,就成了某些程序员的执念。但是,从软件工程的角度来看,这种办法绝对是噩梦,不但其他人无法理解,自己过⼀段时间也会挠头。

那到底该怎么“克制”呢?我的经验有以下三点。

第⼀,能用普通字符串处理的,坚决⽤普通字符串处理字符串处理的速度不见得差,可读性却好上很多。如果要在大段文本中定位所有的today或者tomorrow,用最简单的字符串查找,直接找两遍,明显比to(day|morrow)看起来更清楚。

第⼆,能写注释的正则表达式,⼀定要写注释。正则表达式的语法非常古老,不够直观,为了便于阅读和维护,如今大部分语言里都可以通过x打开注释模式。有了注释,复杂正则表达式的结构也能一目了然。

第三,能用多个简单正则表达式解决的,⼀定不要苛求用一个复杂的正则表达式。这里最明显的例子就是输入条件的验证。比如说,常见的密码要求“必须包含数字、小写字母、大写字母、特殊符号中的至少两种,且长度在8到16之间”。

你当然可以绞尽脑汁用一个正则表达式来验证,但如果放下执念,⽤多个正则表达式分别验证“包含数字”“包含小写字母”“包含大写字母”“包含特殊符号”这四个条件,要求验证成功结果数大于等于2,再配合一个正则表达式验证长度,这样做也是可行的。虽然看起来繁琐,但可维护性绝对远远强于单个正则表达式。

小结

好了,到此为⽌,我的经验介绍完了,可以交棒了。

这些年,很多人问过我,我当时到底是怎么学会正则的?说实话,我那会儿根本没想什么,纯粹出于“干一行爱一行”的朴素想法。要用得多,就找书来,哪怕是囫囵吞枣,也要一鼓作气看完。我一直觉得,真正值得学的东西,没有什么“平滑学习曲线”。在前面的阶段,你总得狠下心来,过了一个又一个坎儿,然后才能有一马平川。

我觉得,正则表达式属于“没有维护成本”的技能。一旦学会了,每⼀次遇到这类问题都可以“零成本出击”。所以,长期来看,这绝对是一笔“无本万利”的生意。希望你能通过这个专栏早日达到一马平川!

精选留言

  • crown

    2020-06-09 09:33:04

    我一直觉得要想掌握一门技术永不忘记,最好的办法是造一个出来,影响我最深的2本书<操作系统真相还原>
    <自制编程语言-基于c语言>,真正把线程,进程,文件系统实现一遍,而且能运行,那这个知识点怕你一辈子也忘不了。
    作者回复

    👍🏻

    2020-06-10 01:14:01

  • Warn

    2020-06-08 17:37:22

    学习入门流程:
    第一步,做分解。
    第二步,分析各个子问题。
    第三步,套皮。
    第四步,调试。

    学会保持克制:
    第⼀,能⽤普通字符串处理的,坚决⽤普通字符串处理。
    第⼆,能写注释的正则表达式,⼀定要写注释。
    第三,能⽤多个简单正则表达式解决的,⼀定不要苛求⽤⼀个复杂的正则表达式。
    作者回复

    优秀👍🏻

    2020-06-08 23:46:33

  • 卡尔

    2020-06-15 19:16:31

    个人学习方法,不管会不会,先过一遍。把名词认识。第二遍把名词串起来。第三遍,总结加理解。
    作者回复

    很好的方法,感谢分享

    2020-06-17 01:05:47

  • 蚂蚁内推+v

    2020-06-10 13:22:30

    > 第⼆,能写注释的正则表达式,⼀定要写注释。正则表达式的语法非常古老,不够直观,为了便于阅读和维护,如今⼤部分语⾔⾥都可以通过 x 打开注释模式。有了注释,复杂正则表达式的结构也能⼀⽬了然。

    老师,您说的注释是是第三方语言在使用正则是对于正则的注释,还是说正则支持注释啊,您的 x 打开注释模式没明白啥意思,谢谢老师。
    作者回复

    x模式就是注释模式,这个模式下可以把复杂的正则展开,每个部分写上注释,这样就清晰了

    2020-06-12 00:23:28

  • 花生无翼

    2020-06-09 08:25:21

    短时间,高强度,一次性学会
    作者回复

    加油

    2020-06-10 01:04:30

  • 愤毛阿青

    2020-06-08 19:21:53

    to(day|morrow)
    这是开启了正则痴迷开关阿;)
    作者回复

    哈哈,真爱才这么写,不过不建议这么用

    2020-06-08 23:47:40

  • 追风筝的人

    2020-10-22 15:40:47

    加油 正则一直觉得难 希望这个专栏可以解决 只会搜索的习惯
    作者回复

    加油,相信可以的

    2020-10-28 23:36:58

  • 卖烧烤夫斯基

    2020-08-09 15:41:53

    余老师的博客都看完了。
    作者回复

    666

    2020-08-13 07:26:57

  • 锐来锐好

    2020-07-08 15:05:25

    老师的声音很好听哈哈
    作者回复

    :-) 专业的播音员

    2020-07-09 23:57:20

  • 一条鲁蛇🐍

    2020-06-10 20:49:14

    怪不得老师的名字这么熟悉,原来正则指引就是老师写的...虽然一直没学会...这次再交学费来了....
  • GJXAIOU

    2024-05-01 16:13:33

    - 如何学习正则:
    - 一次性多投入时间,由表及里,由术及道,掌握方法,具体逻辑可以参考文档;
    - 需要摆脱字符的限制,深入到概念思维的层面;

    - 解决正则问题的步骤:
    - 分解为子问题;
    - 分析各个子问题;
    - 套皮;即用各个语法来实现子问题的处理;
    - 调试;

    - 克制使用正则的原则:
    - 能用简单字符串处理的,就不用正则;
    - 正则表达式要开启 X 模式写注释;方便理解正则的含义;
    - 能用多个简单正则实现的,就不要用一个复杂的正则;
  • ifelse

    2022-11-15 11:46:25

    我一直觉得,真正值得学的东西,没有什么“平滑学习曲线”。在前面的阶段,你总得狠下心来,过了一个又一个坎儿,然后才能有一马平川。--记下来
  • ifelse

    2022-11-15 11:45:18

    学习打卡
  • Leolee

    2021-04-16 14:32:17

    一次性投入大量时间精力学习!后面就长期受益了!
    1、能简单处理的就不要复杂化,这是利人利己的。
    2、写注释,这样结构清晰可见。
    3、熟能生巧!
    未来一个星期,加油!
    作者回复

    加油

    2021-04-21 09:20:55

  • 咱是吓大的

    2020-11-16 13:31:10

    写正则表达式越简单越好,简单是为了读起来方便,改起来也方便
  • AI悦创

    2020-06-22 14:16:26

    x 打开注释模式,老师能不能演示一下呢?Python 的,谢谢老师。
    作者回复

    后面匹配模式里面有

    2020-06-23 01:25:16

  • hao-kuai

    2020-06-11 14:18:27

    关于4步流程。
    借用老师的一句话这是做软件开发基本流程。之前的难懂难学说到底还是重视程度不够,没能正视它的存在,更多的是“白瞟”,没能进入正则的世界。不清楚正则的知识图谱或者叫世界观,不清楚正则处理问题思路、正则的工具。与其纠结正则符号,不如学习正则的思维。

    关于克制。
    1、能简单处理的不能因炫技复杂化,就像一句白话文能说清楚非要拽文言文或者诗词,除了“酸”之外会引来更多的问题。
    2、注释肯定要写,要写,要写!
    3、分开写!代码是写给人看的,分开写就是积德行善了。
    作者回复

    👍🏻

    2020-06-12 00:26:36

  • fjf--

    2020-06-10 11:10:53

    希望两位老师能够结合本课程和<正则指引>讲讲长期的学习和提高路线.
    作者回复

    一次性多投入时间和精力,掌握了核心思想,概念模型之后,后面就是查阅文档,很容易解决问题了。
    后面就是长期受益了,日常使用的话不要长期投入,书籍可以放手边参考。

    2020-06-12 00:34:40

  • 草原牧哥

    2020-06-10 10:31:49

    余老师写的书一版和二版都买了,翻译的书也买了,感觉还是学不下去,这次但愿能有质的飞跃。
    作者回复

    正则其实并不难,主要是一些功能怎么理解,怎么记忆。这个课程会尽量以通俗易懂的方式去讲,同时会给出一些记忆技巧。
    但最终你要想很好掌握,还得自己多加练习,多尝试理解更深刻。一起努力学好正则,加油!

    2020-06-12 00:20:46

  • 设置昵称

    2020-06-10 00:49:50

    克制最重要,复杂的正则一定要有注释,对自己负责也对同事负责
    作者回复

    对的

    2020-06-11 00:01:59