易燃物汇聚 YouTube 有声书与书评
正则指引 封面

正则指引

余晟著

1723人在读
27.3万字总字数
¥23.2定价

内容简介

目前国内IT领域用到搜索的场景有很多,这样也就自然而然涉及了正则表达式的应用。作者将开发中遇到的实例,以及其他人咨询的问题,总结出一套正则表达式解题的办法,并通过一些具体的例子,讲解使用,能指导读者拆解、分析问题,另外也有关于效率的经验总结。本书分为三大部分,共17章,2个附录。其中不但阐述了正则表达式的基数应用,还涉及正则表达式的匹配原理、逻辑问题、常见操作和效率问题。

读者书评

★★★★★

《正则指引》拆解 作者:余晟 一、一句话概括 写正则表达式不是凭感觉堆叠符号,而是先把需求拆成字符范围、位置、重复次数和上下文约束,再根据引擎的匹配与回溯原理构造既正确又高效的模式。 二、核心逻辑 全书分为三部分: 1. 基础语法:字符、量词、括号、断言、匹配模式及其他常用特性。2. 原理与解题:正则引擎怎样匹配、遇到问题怎样拆解、如何避免效率陷阱。3. 编程语言实践:Java、JavaScript、PHP、Python、Ruby和Linux/UNIX中的正则差异。 核心路径可以概括为: 明确需求 → 划分字符与位置 → 写出基本结构 → 增加重复和分支 → 加入上下文约束 → 用正反例测试 → 检查回溯与性能 → 根据语言引擎调整 三、核心内容 1. 正则表达式描述的是文本模式 正则表达式不是一段普通文本,而是一种用于描述字符串集合的小型语言。 它常用于: 验证格式;搜索文本;提取字段;替换内容;切分字符串;清洗日志;批量重构;语法高亮;简单词法分析。 使用前要先确定任务是“查找”“提取”“替换”还是“验证”,因为对应正则的边界要求不同。 2. 普通字符与元字符必须区分 大多数字符表示自身,某些符号具有特殊意义,例如: . 匹配任意字符;*、+、? 表示重复;[] 表示字符组;() 表示分组;| 表示分支;^、$ 表示位置;反斜杠用于转义。 如果要匹配元字符本身,通常需要转义。 正则字符串还可能经过编程语言字符串层的转义,因此要区分“正则转义”和“字符串转义”。 3. 字符组表示某个位置允许出现哪些字符 字符组如[abc]表示当前位置可以是a、b或c。 范围如[0-9]表示数字,否定字符组如[^0-9]表示非数字字符。 常用简写包括: d:数字;w:单词字符;s:空白字符。 不同引擎和Unicode模式对“数字”“单词字符”的定义可能不同,不能永远假设只包含ASCII。 4. 点号的含义受模式影响 . 通常匹配除换行之外的任意字符。 启用单行或DOTALL模式后,它可能匹配换行。 如果想表示真正的任意字符,也可以根据引擎使用更明确的写法。 过度使用.*会让匹配范围过宽、错误难以发现,并可能带来严重回溯。 5. 位置锚点不消耗字符 ^和$匹配字符串或行的开头、结尾,它们描述位置,而不是具体字符。 格式验证通常需要完整锚定。例如,只写一个日期片段模式,可能在包含额外垃圾字符的字符串中也匹配成功。 不同引擎还可能提供绝对字符串开头和结尾锚点,避免多行模式改变^和$的语义。 6. 单词边界也是一种位置条件 通常表示单词字符与非单词字符之间的位置。 它适合匹配完整英文单词,避免在更长单词内部命中。 但在中文、混合语言和Unicode文本中,单词边界行为可能不符合自然语言的“词”。 正则边界是字符分类结果,不是真正的分词器。 7. 量词描述重复次数 常见量词包括: ?:零次或一次;*:零次或多次;+:一次或多次;{m}:恰好m次;{m,n}:m到n次;{m,}:至少m次。 量词作用于紧邻的字符、字符组或分组。 设计量词时应尽量给出合理上下限,无边界的重复更容易误匹配和产生性能问题。 8. 贪婪量词先尽可能多地匹配 大多数普通量词默认是贪婪的。 例如,.*会先尝试吞下尽可能多的字符,如果后续无法匹配,再逐步吐出字符回溯。 贪婪并不等于永远匹配最长结果,而是在当前正则结构和引擎规则下优先尝试更多字符。 理解“先多取、失败后回退”,是理解许多意外结果的关键。 9. 懒惰量词先尝试尽可能少地匹配 在量词后加?,通常把它变成懒惰量词,例如.*?。 它先取得尽可能少的字符,只有后续无法匹配时才逐步扩展。 懒惰量词适合限制区间,但并不是性能优化万能药。它同样可能反复尝试和回溯。 更可靠的方法通常是使用明确排除终止符的字符组。 10. 占有量词和原子分组可以阻止回溯 部分引擎支持占有量词或原子分组。 它们一旦匹配一段文本,就不允许引擎退回重新分配。 这可以: 提高性能;防止错误回溯路径;明确表达某段匹配不可撤销。 但使用不当也可能让本来可以成功的表达式失败。 是否支持这些特性,要根据具体语言和引擎确认。 11. 分组控制量词和分支范围 圆括号可以把多个元素组合为一个整体。 例如,对整个单词或子模式应用量词时,需要先分组。 分组也会影响|的作用范围。若不加括号,分支可能覆盖比预期更大的部分。 复杂正则应通过分组明确层次,而不是依赖读者猜测运算优先级。 12. 捕获组用于提取匹配内容 普通括号通常会记录内部匹配的文本。 捕获组可用于: 提取日期的年、月、日;获取键和值;在替换中重新组合;在程序中访问子匹配;供后续反向引用使用。 如果分组只为了控制结构,不需要提取,应优先使用非捕获组,减少编号变化和不必要开销。 13. 命名分组提高可读性 与数字编号相比,命名分组可以用有意义的名称访问内容。 例如,日期可以命名为year、month和day。 命名能够: 减少组编号错位;提高代码可维护性;让替换模板更清晰;支持复杂解析。 不同语言的命名语法和引用方式可能不同,需要查阅对应文档。 14. 反向引用要求后文重复前面实际匹配的内容 反向引用不是再次执行组内的正则,而是匹配捕获组已经得到的具体文本。 它可以用于: 查找重复单词;匹配成对引号;检查分隔符一致;识别重复片段。 反向引用增强了表达能力,也可能显著增加回溯复杂度。部分DFA型工具不支持它。 15. 分支表示多个候选模式 A|B表示尝试A或B。 许多回溯型引擎会按书写顺序尝试分支,因此顺序可能影响结果和性能。 公共前缀可以提取到分支之外,减少重复。 分支过多时,正则会变得难以维护,可能更适合使用代码、字典或解析器。 16. 断言检查上下文但不消耗文本 先行断言和后行断言用于判断当前位置前后是否满足条件。 常见类型包括: 正向先行:后面必须出现某模式;负向先行:后面不能出现某模式;正向后行:前面必须出现某模式;负向后行:前面不能出现某模式。 断言适合表达“前面是什么”“后面不能是什么”等上下文限制。 后行断言在不同引擎中的支持和长度限制差异较大。 17. 断言可以组合多个独立条件 验证字符串时,可以在同一位置叠加多个先行断言。 例如,密码规则可能分别要求: 至少一个数字;至少一个字母;不包含空格;总长度在范围内。 断言让各条件相互独立,但过度叠加会降低可读性,并可能造成性能问题。 复杂业务验证通常应由正则和程序逻辑共同完成。 18. 匹配模式会改变相同正则的行为 常见模式包括: 忽略大小写;多行模式;单行/DOTALL模式;自由间距或注释模式;Unicode模式。 多行模式通常改变^和$,单行模式则改变.。 自由间距模式可以把复杂正则拆成多行并添加注释,但空格本身的匹配方式也会改变。 使用模式时,应在代码或文档中明确标注。 19. 回溯型引擎按照尝试路径工作 Java、JavaScript、Python、PHP等常见环境多使用回溯型正则引擎。 引擎通常从某个位置开始,按照正则顺序尝试: 1)当前元素匹配;2)继续下一个元素;3)后续失败;4)回到之前可选择的位置;5)改用另一种长度或分支;6)重新尝试。 正则不是一次性“理解”整个字符串,而是在可能路径中搜索。 20. NFA和DFA引擎具有不同特征 简化而言: 回溯型NFA重视表达式顺序,支持捕获、反向引用和断言等丰富功能;DFA通常并行维护状态,匹配性能更稳定,但功能可能受限。 不同工具即使都称为正则表达式,也可能采用不同引擎和语法。 优化和兼容性判断必须知道实际使用的引擎。 21. 灾难性回溯来自模糊路径爆炸 当多个可重复结构可以用许多方式划分同一文本时,引擎可能尝试指数级组合。 危险结构常包括: 嵌套量词;重叠分支;宽泛的.*;可为空的重复项;失败发生在很后面;对长输入缺少边界。 这不仅导致程序缓慢,还可能形成正则拒绝服务漏洞。 22. 优化正则首先要减少不确定性 常见优化方法包括: 使用更具体的字符组;增加明确锚点;限制量词范围;避免嵌套的模糊重复;把容易失败的条件提前;提取公共前缀;使用原子分组或占有量词;将复杂任务拆成多步;选择性能更可控的引擎。 优化不是把正则写得更短,而是减少引擎需要尝试的路径。 23. 解题应从自然语言需求开始拆分 面对一个匹配问题,可以依次询问: 1)要匹配的对象是什么?2)字符范围是什么?3)哪些部分必须出现?4)哪些部分可选?5)重复多少次?6)开头和结尾有什么要求?7)前后文有什么限制?8)是否需要提取子内容?9)有哪些合法与非法示例?10)输入长度和性能要求是什么? 先写出结构,再逐步增加细节,比一次写出复杂表达式更可靠。 24. 验证、查找和提取不能混为一谈 同一个业务对象,在不同任务中需要不同正则。 查找:允许在大段文本中找到局部;验证:通常要求完整字符串符合规则;提取:需要设计捕获组;替换:需要考虑替换模板和组引用;切分:关注分隔符和空字段。 如果用查找正则进行验证,常会接受额外字符。 25. 正则并不适合解析所有结构 正则适合局部、规则相对稳定的文本模式。 对于深度嵌套、完整编程语言、复杂HTML和需要语义状态的格式,正则往往难以安全维护。 这类任务更适合: 专用解析器;DOM;词法和语法分析器;JSON/XML库;分步骤程序逻辑。 “能用正则勉强完成”不等于“应该用正则完成”。 26. 邮箱、URL和日期验证应明确业务边界 现实格式可能比简单示例复杂得多。 例如,完整邮箱规范支持许多少见形式;日期还需要检查月份和闰年;URL包含编码、端口和国际化域名。 实际产品应先决定需要支持的范围,再选择: 简化正则;标准库;解析器;二次业务验证。 正则适合先筛选格式,不一定负责全部语义正确性。 27. Java中的反斜杠通常需要双重转义 在Java源代码中,正则首先是字符串字面量,再交给正则引擎。 因此,一个正则反斜杠通常需要在字符串中写成双反斜杠。 Java提供Pattern与Matcher等API,并支持分组、查找和替换。 工程中应预编译重复使用的模式,避免每次请求重新编译。 28. JavaScript正则适合浏览器与Node.js文本处理 JavaScript可以使用正则字面量或RegExp构造器。 两种方式的转义层次不同:构造器参数作为字符串时需要额外转义。 现代JavaScript逐步增加命名组、后行断言和Unicode等支持,但旧运行环境可能不兼容。 全局模式还可能改变lastIndex状态,重复使用时需要注意。 29. PHP的preg系列通常基于PCRE PHP常用preg_match、preg_replace和preg_split等函数。 模式通常需要分隔符,并可以添加模式修饰符。 PCRE功能丰富,支持多种断言、原子组和命名组。 在Web环境中,必须限制输入长度和正则复杂度,防止回溯型拒绝服务。 30. Python的re模块强调原始字符串 Python中常使用原始字符串书写正则,减少字符串转义干扰。 常用操作包括: search:查找;match:从开头匹配;fullmatch:完整匹配;findall/finditer:批量查找;sub:替换;split:切分。 应注意Python标准re与第三方regex模块并非完全相同。 31. Ruby把正则深度融入字符串处理 Ruby提供正则字面量和便捷的匹配、替换接口。 捕获组和全局匹配状态使用方便,但隐式状态可能降低可读性。 复杂项目中,仍应把模式命名、添加测试,并避免散落在业务代码中。 32. Linux/UNIX工具存在多种正则方言 grep、sed、awk等工具使用的正则语法并不完全相同。 需要区分: 基本正则表达式;扩展正则表达式;PCRE兼容模式;工具自身的转义规则。 把某语言中的正则直接复制到命令行,可能因方言不同而失败。 使用前应确认工具选项和实际引擎。 33. 正则必须使用正反例测试 测试集至少应包含: 最简单合法输入;最长合法输入;每个可选分支;边界值;空字符串;多行和Unicode;看似接近但非法的输入;超长恶意输入;可能触发回溯的输入。 只有合法示例通过,不能证明正则正确;还要验证它能拒绝非法数据,并在长输入上保持合理性能。 34. 可读性是正则质量的重要组成 可维护正则应采用: 命名;注释;非捕获组;命名捕获组;自由间距模式;分步骤匹配;配套测试;业务规则说明。 如果一个表达式只有作者本人能看懂,它就是未来的维护风险。 四、本书最值得关注的核心观点 本书最值得关注的观点是: 正则表达式的性能和正确性,取决于你给引擎留下了多少种可能的尝试路径。 .*、嵌套量词和重叠分支之所以危险,不是因为符号本身,而是因为同一段文本可以被许多方式划分;当末尾匹配失败时,引擎会回头尝试大量组合。 因此,优秀正则不是最短的正则,而是边界清晰、歧义较少、便于解释和测试的正则。 五、一段话总结 《正则指引》从字符组、转义、量词、分组、捕获、反向引用、分支、锚点、单词边界和前后行断言入手,进一步解释贪婪、懒惰、占有量词以及NFA回溯型引擎的匹配过程,并总结验证、查找、提取、替换和切分等常见任务的拆解方法。全书最重要的实践原则,是先用自然语言明确字符、位置、次数和上下文,再逐步写正则,并用合法、非法、边界和恶意长输入测试;性能优化则要减少重叠分支、宽泛通配和嵌套量词造成的回溯路径。Java、JavaScript、PHP、Python、Ruby和Linux工具在语法、转义和功能上并不完全相同,因此正则必须根据实际引擎编写。正则是强大的文本模式工具,但复杂嵌套和完整结构解析应交给专用解析器。

★★★★★

内容很细,从易到难,循序渐进,语言部分总结其实可以挑选自己需要的看,看太多容易混淆,linux部分可以一看。附录的例子走马观花的看一遍即可,自己写出来才是最好的。花了20个小时终于读完了,主要是一些概念,需要记得太多,有些例子看着也会晕乎,但坚持读下去,就会慢慢都理解。书中唯一的缺点,部分内容重复,或感觉介绍的过多,比如语言部分占了半本书了,而且连同一语言的不同版本差异都有介绍,太细了,我认为这里有点过分细致了。不过 还是值得一读,一定要坚持读。

★★★★★

对正则讲的非常全面,由浅入深 作者讲解的很细致初学者都能看懂

★★★★★

工具类书。还是实践为好!不过也学了点东西

★★★★★

如果你刚接触正则表达式,感觉无从下手,那就快来读一下这本书吧!

★★★★★

看了一二部分的正则表达式原理及第三部分python中正则的用法,正则表达式的内容几乎面面俱到,知识点也讲解得非常透彻。自己日常工作中处理文本经常用到正则表达式,看此书时才感觉之前对正则表达式的理解只是九牛一毛。个人不推荐新手从此书开始学习正则表达式,内容太多会抓不住重点。

★★★★★

这本书非常不错,也很少见,其中提出的不同情况下的正则表达式的推演我很推崇。后面针对不同语言的部分没看,后面用到的时候在翻

★★★★☆

日本人的书要么啰嗦得很要么细腻得很 这本属于后者

☆☆☆☆☆

这本书教会我如何思考并构造正则表达式

★★★★☆

很全面的讲解了正则表达式的用法!后续慢慢的用上[微笑]

书籍信息

作者余晟著
出版社电子工业出版社
出版时间2012-05-01
ISBN9787121165511
分类计算机-编程设计
格式EPUB
完结状态连载中
章节数24