正则表达式入门课
涂伟忠
高级研发工程师
24700 人已学习
新⼈⾸单¥59
登录后,你可以任选2讲全文学习
课程目录
已完结/共 18 讲
正则表达式入门课
15
15
1.0x
00:00/00:00
登录|注册

05 | 断言:如何用断言更好地实现替换重复出现的单词?

环视与子组
单词边界用环视表示
示例:邮政编码提取
环视概念
示例:日志起始行判断
\z 整个字符串的结尾
\A 整个字符串的开头
$ 行的结束
^ 行的开始
示例:tom 替换成 jerry
\b
环视
行的开始或结束
单词边界
课后思考
总结
断言
如何用断言更好地实现替换重复出现的单词?

该思维导图由 AI 生成,仅供参考

你好,我是伟忠。今天我来和你聊聊正则断言(Assertion)。
什么是断言呢?简单来说,断言是指对匹配到的文本位置有要求。这么说你可能还是没理解,我通过一些例子来给你讲解。你应该知道 \d{11} 能匹配上 11 位数字,但这 11 位数字可能是 18 位身份证号中的一部分。再比如,去查找一个单词,我们要查找 tom,但其它的单词,比如 tomorrow 中也包含了 tom。
也就是说,在有些情况下,我们对要匹配的文本的位置也有一定的要求。为了解决这个问题,正则中提供了一些结构,只用于匹配位置,而不是文本内容本身,这种结构就是断言。常见的断言有三种:单词边界、行的开始或结束以及环视。

单词边界(Word Boundary)

在讲单词边界具体怎么使用前,我们先来看一下例子。我们想要把下面文本中的 tom 替换成 jerry。注意一下,在文本中出现了 tomorrow 这个单词,tomorrow 也是以 tom 开头的。
tom asked me if I would go fishing with him tomorrow.
中文翻译:Tom 问我明天能否和他一同去钓鱼。
利用前面学到的知识,我们如果直接替换,会出现下面这种结果。
替换前:tom asked me if I would go fishing with him tomorrow.
替换后:jerry asked me if I would go fishing with him jerryorrow.
这显然是错误的,因为明天这个英语单词里面的 tom 也被替换了。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了如何使用断言来更好地实现替换重复出现的单词。通过讲解断言的概念,包括单词边界、行的开始或结束以及环视三种常见的断言,读者能够快速了解断言的使用方法和技术特点。文章通过实际例子和技术原理的讲解,帮助读者更好地掌握了正则中断言相关的内容。通过对单词边界、行的开始或结束、环视的详细讲解和实例代码,读者可以更好地理解断言的使用方法和技术特点。文章内容深入浅出,为读者提供了全面的学习体验。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《正则表达式入门课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(68)

  • 最新
  • 精选
  • Robot
    (?<=\W)\w+(?=\W)无法包含首尾两个单词,看在线示例,请老师解惑 https://regex101.com/r/jI12j0/1

    作者回复: 这个问题确实很有意思,写成 !\w 是可以的。 https://regex101.com/r/jI12j0/2 我一直认为 \w 反面就是 \W ,但查资料发现,\W 不能匹配行开关和结尾,后面会更正一下。 参考:https://stackoverflow.com/a/11874614/2714931 \W would match any non-word character and so its easy to try to use it to match word boundaries. The problem is that it will not match the start or end of a line.

    2020-06-23
    4
    18
  • 唐龙
    vim: /\v<(\w+)%(\s+\1)+> vim末行模式中的环视: (...)@= (...)@! (...)@<= (...)@<! 分别对应文中的: (?=...) (?!...) (?<=...) (?<!...) 如果我们想匹配cat2和hat2,可以使用: /\v<\w+(\d)@= (其中/\v可无视) 用文章中的正则: \b\w+(?=\d)

    作者回复: 感谢分享,解释一下,\v 是 vim 中的 very magic 模式,避免很多符号的转义,但 {} 还是得转义。

    2020-06-22
    13
  • 张瑞红
    \b(\w+)\s\1\b ,测试链接https://regex101.com/

    作者回复: 赞

    2020-06-26
    4
    9
  • seerjk
    老师文中单词边界的Python例子有点问题,patten 应该以r开头,r"\btom\b" ``` import re test_str = "tom asked me if I would go fishing with him tomorrow." replace_str = 'jerry' result = re.sub(r"\btom\b", repl=replace_str, string=test_str) print(result) ```

    作者回复: 你好,正则部分不是必须加 r 的,加 r 表示原始字符串,一般是建议加 r,如果涉及比较复杂的转义会容易些。 这部分内容在转义一节中有提到,感谢你的反馈。🌹

    2020-06-25
    3
    3
  • 斯盖丸
    老师,环视和直接写有什么区别呢?比如(?<=Y),我直接写Y不就完事了吗,还有(?<!Y),我直接写[^Y]也可以吧。为何还要这样多此一举呢?

    作者回复: 对要匹配的字符环境有要求,这时候用环视。 直接写的话确实可以提取出来,还得二次处理下

    2021-02-03
    3
    2
  • seerjk
    思考过程: v1: 错误版本 (\b\w+\b) \1 ,实际测试还是能匹配到 cat cat2 情况,错在应该对分组后的引用\1加边界限制。 v2: (\w+) \b\1\b 还有优化空间,2个重复单词间的空字符不一定是空格,还可能是 换行符,制表符等。测试链接:https://regex101.com/r/lVOdaq/4 v3: (\w+)\s\b\1\b 在v2基础上优化了空字符匹配。测试链接:https://regex101.com/r/lVOdaq/2

    作者回复: 👍🏻,思路清晰

    2020-06-25
    2
  • 这里是有个问题的,是这样的: 如果匹配的字符串为: the little cat cat you. 这时候是两个 cat ,正则可以这样的写:\b(\w+)\b\s+\b\1\b 但是这时候如果要匹配的字符串为 the little cat cat cat you 上面的正则就不行了 ,需要改为:\b(\w+)\b\s+(\b\1\b\s+)+ ; 但是这时候如果 在添加第四个 cat 且和前面的cat 之间的空格不是一个了,匹配又不行了, 这是因为 括号后面的 + 代表出现括号内的大于一次,但是后面的空格数不一致了,就匹配不上了 这个应该怎么解决的?

    作者回复: 把单词之间的空白符号,放到后面的重复里面去。 \b(\w+)\b(\s+\b\1\b\s+)+

    2020-06-23
    2
    2
  • felix
    没什么基础,看完了这几期课程,还是有点晕。有个例子想老师帮我看看: 我想拿到script里的一个变量,script如下所示: <script> var para = { a: 'test;test', }; function funtest { }; </script> 目标是拿到para这个变量,想法是拿到第一个};前的内容,但是目前只会拿到第一个;前的内容,但是;有时会出现在引号里面,想问下老师怎么修改如下python正则 var para = ([^;]+);

    作者回复: 这个问题需要去试,根据实际情况来不断完善正则,比如这样 https://regex101.com/r/md2A4p/1

    2020-06-22
    3
    1
  • Geek.S.
    老师,我有几个疑问: 1. 环视的匹配原理是怎么样的? 2. 环视有 lookahead 和 lookbehind,那么 lookahead 是不是一定不能放在正则的最后面(放在最后面一定匹配不到)?lookbehind 是不是一定不能放在最前面(放在最前面一定匹配不到)? 3. ^ 和 \A,都表示匹配字符串的开头,我测试了一下,\A 是匹配所有串的开头,请问在 single line 模式下,^ 和 \A 是不是完全等价?($ 和 \Z 同理) 在[维基百科](https://zh.wikipedia.org/wiki/正则表达式)上 `(?<=pattern)` 叫 look behind; 再去看一下 python re 库官方文档英文版,这个也叫 positive lookbehind assertion; 而在老师的文稿里,这个叫 positive lookahead,看上去像是现在不同的角度看的: 站在断言看正则表达式,或站在正则表达式看断言。反正到这里我蒙圈了。 我想,如果明白了概念和匹配原理, 对命名和使用场景都有一个准确的认识后,就不会被弄得稀里糊涂了。 希望老师能解答一下上面几个问题,谢谢老师! 课后习题: 模式: (\b\w+\b)([ ]+\1\b)+ 替换: \1 https://regex101.com/r/pz02ua/8

    作者回复: 感谢指出这个问题,英文名称的问题我来改一下。 一般只要记住有左尖括号是向左看就好了,behind 和ahead 这种向前和向后看的说法确实很绕。 匹配原理部分等后面的课程会具体讲解,后面可以关注一下。 习题 (\b\w+\b)([ ]+\1\b)+ 这个可以优化一下,如果中括号里面只有一个空格,中括号是没必要的,可以写成 (\b\w+\b)( +\1\b)+ 但也可能是换行之类的,另外第二部分没必要保存成子组,可以进一步优化成 (\b\w+\b)(?:\s+\1\b)+

    2020-06-22
    1
  • 虹炎
    我的答案: (\w+)(\s+\b\1\b) 使用全局匹配。

    作者回复: 对的,可以想一下,第二个括号是必须的么?需要保存成子组么?

    2020-06-22
    6
    1
收起评论
显示
设置
留言
68
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部