作者:kamly,腾讯 CDC 应用开发工程师

前言

正则表达式在我们日常的软件开发过程中被广泛使用,例如编写 Nginx 配置文件、在 Linux 与 macOS 下查找文件,然而不同软件不同操作系统对于正则的应用有着不一样的行为,主要原因是正则表达式演进过程中,出现 POSIXPCRE 派系之分。

一、历史

先了解一下正则表达式的演进史。

20 世纪 40 年代,两位神经生理学家 Warren McCulloch 和 Walter Pitts,研究出了一种用数学方式来描述神经网络的方法,可以将神经系统中的神经元描述成小而简单的自动控制元。

50 年代,一位叫 Stephen Kleene 的数学家在 McCulloch 和 Pitts 早期工作的基础上,发表了《神经网络事件表示法和有穷自动机》 论文。这篇论文描述了一种叫做 "正则集合(Regular Sets)" 的数学符号,引入了正则表达式的概念。

60 年代,Unix 之父 Ken Thompson 发表了 《正则表达式搜索算法》 论文。并且根据这篇论文的算法,将正则引入到编辑器 qed ,以及之后的编辑器 ed 中,然后又移植到了我们熟悉的文本搜索工具 grep 中。

70 年代,由于 grep 支持的功能不多,因此 Alfred Aho 编写了 egrep 程序(其中 e 表示加强版的意思)。在 grep 、 egrep 发展的同时, awk 、 lex 、 sed 等异军也开始凸起,每个程序所支持的正则表达式都有差别。

80 年代,POSIX (Portable Operating System Interface) 标准公诸于世,它制定了不同的操作系统都需要遵守的一套规则,其中就包括正则表达式的规则。遵循 POSIX 规则的正则表达式,称为 POSIX 派系的正则表达式。Unix 系统或类 Unix 系统上的大部分工具,如 grep 、sed 、awk 等都属于 POSIX 派系。同样在 80 年代,Larry Wall 发布了 Perl 编程语言,其中引入的正则表达式功能是颗耀眼明珠。

90 年代,随着 Perl 语言的发展,它的正则表达式功能越来越强悍。为了把 Perl 语言中正则的功能移植到其他语言中, PCRE (Perl Compatible Regular Expressions)派系的正则表达式也诞生了。现代编程语言如 Python , Ruby , PHP , C / C++ , Java 等正则表达式,大部分都属于 PCRE 派系。

总的来说,经历 20 世纪 80 至 90 年代洗礼,正则表达式形成了两大派系:POSIXPCRE

正则表达式演进史

二、POSIX 与 PCRE

POSIX 派系 与 PCRE 派系具体有什么不一样?我们应该何时选择哪个派系?

POSIX 派系

POSIX 派系是遵循 POSIX 规则的正则表达式,其中代表软件有:grep ,sed 和 awk 等。

BRE 和 ERE 标准

POSIX 派系分为两种标准:

  1. BRE 标准(Basic Regular Expression 基本正则表达式)

  2. ERE 标准(Extended Regular Expression 扩展正则表达式)

在 GNU 版本下,两者具体差别如下:

BRE 和 ERE 对比

是不是很难找到两者的差别点呢?仔细留意一下,第 3,4,5,7 行的内容。我们能发现,如果使用 BRE 标准,需要对 [], (), | 符号进行转义。作者看来 ERE 实际上是 BRE 的一个扩展标准,开发者使用 ERE 能书写更简单的正则表达式,不需要对某些字符进行特殊转义。

POSIX 字符组

POSIX 派系有自己的字符组,叫 POSIX 字符组,具体解释如下所示:

POSIX字符组

篇幅原因,仅提供部分需要关注的对比,具体看【附录-POSIX 字符组详细内容】。

PCRE 派系

现代编程语言大部分都属于 PCRE 派系,如 Python , PHP 和 Java 等。

PCRE 与 Perl
  • Perl1 提供了正则表达式操作符——是通用脚本语言的首创;

  • Perl2 补充 /i 量词,能够进行不区分大小写匹配等;

  • Perl3 支持 /e 量词,能够增强替换运算符的能力;{min,max} 区间量词等;

  • Perl5 添加 非捕获的括号,忽略优先的量词,顺序环视功能等。

随着 Perl 每次迭代,新增的特性使正则表达式本身逐渐成为一门强大的编程语言,并为其提供了进一步发展空间,也因为派系的整合, PCRE 库横空出世,它是一套兼容 Perl 正则表达式库,全面仿制 Perl 的正则表达式的语法和语义。其他开发人员可以把 PCRE 库整合到自己的工具和语言中,为使用者提供丰富的正则功能。

特性
  1. 更易用

    相对于 POSIX 派系的 BRE 标准,不需要使用 \ 进行转义。

    例如:在多选分支结构直接使用 | 即可(1|2 表达 1 或者 2)

  2. 更简洁

    在兼容 POSIX 字符组的基础上还支持更简洁的写法。

    例如:\w 等价于 [[:word:]]\d 等价于 [[:digit:]]

  3. 更多功能

    例如:Look-around (环顾断言), Non-capturing Group (非捕获组), non-greedy (非贪婪)等。

总结

正因为 PCREPOSIX 相比, PCRE 使用起来更加易用简洁(不需要转义,有更简洁字符组),功能更加丰富(非捕获组,环顾断言,非贪婪)。如果没有特殊原因,应尽可能使用 PCRE 派系,让正则匹配的结果更符合我们预期。

pcre, posix bre, posix ere

篇幅原因,仅提供部分需要关注的对比,具体看【附录-PCRE、GNU BRE、GNU ERE 对比】。如果读者对贪婪和非贪婪模式感兴趣,可以了解一下正则表达式的执行引擎,或许会让你对正则表达式产生新的看法。

三、实战

了解完 PCRE 派系和 POSIX 派系后,我们来做个简单的测试。文本内容如下,我们目标是需要匹配其中的数字:

12345
abcde

实验环境为 Linux 与 macOS 下的 grep ,分别使用:

  • 不带参数,为 POSIX BRE 模式;

  • 带参数 -E,为 POSIX ERE 模式;

  • 带参数 -P,为 PCRE 模式( macOS 不支持)。

实验结果如下图:

实验结论

在 Linux 环境下

通过 man grep ,可以了解到 Linux 下的 grep 默认是 POSIX BRE 模式:

-G, --basic-regexpInterpret PATTERN as a basic regular expression (BRE, see below).  This is the default.

加上 -E 则是 POSIX ERE 模式:

-E, --extended-regexpInterpret PATTERN as an extended regular expression (ERE, see below).

加上 -P 则是 PCRE 模式:

-P, --perl-regexpInterpret the pattern as a Perl-compatible regular expression (PCRE).  This is experimental and grep -P may warn of unimplemented features.
在 macOS 环境下

从实验结果来看, grep '\d' demo.txt' 命令在 Linux 与 macOS 输出是不一样的,这是因为 macOS 自带的 grep 是 BSD 版本,而 Linux 下的 grep 则是 GNU 版本。

macOS 基于 BSD,预置 BSD 工具链,众多命令行工具与 Linux 下 GNU 工具的行为不一致,例如常见的 gzip , find 和 sed ,以及本文重点提及的 grep。

读者如果希望自己的 macOS 电脑能完美运行 GNU/Linux 上的 Shell 脚本,可以使用 homebrew 来逐一替换,例如本文提及的 grep 可以通过 brew install grep

总结

正则表达式以及相关生态在发展了数十年的情况下,应用场景已经非常广泛。读者在使用软件工具的时候,应需要了解该工具支持正则表达式何种派系,避免执行脚本迁移不同环境后运行结果不符合预期。

例如:

  1. 确认版本类型(GNU , BSD)。建议统一使用 GNU 中 grep 程序,避免在不同环境下运行结果不符合预期的现状

  2. 确认每个模式下的选项(BRE , ERE , PCRE)。尽可能选择 PCRE 模式,因为 PCRE 模式更符合我们的使用习惯。

此外,除了关心正则表达式的标准之外,强烈推荐读者细读正则表达式的执行引擎,或许能帮助你写出更性能更好的正则表达式,避免因为正则表达式的地狱回溯导致的应用程序的 OOM。

附录

POSIX 字符组详细内容

POSIX字符组详细内容

PCRE、GNU BRE、GNU ERE 对比

PCRE、GNU BRE、GNU ERE 对比

GNU

GNU简介

BSD

BSD 是加州大学伯克利分校对 Unix 系统进行的扩展与重新发行。目前的 BSD 生态系统围绕三大主要操作系统:

  1. FreeBSD、OpenBSD、NetBSD

  2. DragonFly BSD

  3. 其他发行版

参考资料

  • 《精通正则表达式》第 3 版

  • 07 | 正则有哪些常见的流派及其特性?

  • 正则表达式“派别”简述 - Keep Coding

  • 正则表达式的历史与几大流派 - 小蒋不素小蒋 - 博客园

  • Regex cheatsheet

  • GNU 是什么,和 Linux 是什么关系?- 知乎

  • Difference Between Linux And BSD | Open Source Operating Systems

  • Unix, BSD, GNU 和 Linux 之间是什么关系?- 掘金

  • PCRE、GNU BRE、GNU ERE 对比

招人正则匹配中,欢迎扫码命中

腾讯程序员视频号最新视频

梳理正则表达式发展史相关推荐

  1. 帮你梳理正则表达式的基础知识

    正则表达式在我们平时的工作中相当的常用,无论是写jmeter脚本,或者写自动化脚本,都可能会用到正则表达式.这篇文章主要梳理正则表达式的常用知识点,并结合一些具体的例子,让大家能掌握使用正则表达式的正 ...

  2. javascript 学习并梳理正则表达式姿势之字符串匹配( 一)

    正则表达式字符串匹配相关 引:<JavaScript 正则表达式迷你书> 读老姚丨洞见生产者的<JavaScript 正则表达式迷你书>全是干货好书,通俗易懂,图文结合 正则是 ...

  3. 基于 iframe 的全新微前端方案

    作者:damyxu,腾讯 PCG 前端开发工程师 iframe是一个天然的微前端方案,但受限于跨域的严格限制而无法很好的应用,本文介绍一种基于 iframe 的全新微前端方案,继承iframe的优点, ...

  4. 一篇值得收藏的正则表达式文章

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 关于正则表达式,我一直使用得比较浅,一直也想好好学习下.今天分享的 ...

  5. C#的进化——C#发展史、C#1.0-10.0语法系统性梳理、C#与JAVA的对比

    C#的进化 C#发展史.C#1.0-10.0语法系统性梳理.C#与JAVA的对比 前言 C#也使用了十年有余了. 一路走来,见证了微软从封闭走向开放,从平台捆绑,到成为活跃于Github的重要贡献者. ...

  6. 梳理百年深度学习发展史-七月在线机器学习集训营助你把握深度学习浪潮

    作为机器学习最重要的一个分支,深度学习近年来发展迅猛,在国内外都引起了广泛的关注.然而深度学习的火热也不是一时兴起的,而是经历了一段漫长的发展史.接下来我们了解一下深度学习的发展历程. 1. 深度学习 ...

  7. 『不再迷茫 - 正则表达式』JS正则要点梳理 持续更新

    [TOC] 写在前面 - Lionad 正在看VueJS的源码, 看到了HtmlParser部分, 感觉以前看的正则表达式基础知识已经完全不够用了, 现翻阅博客资料, 将一些JS中正则表达式难用的部分 ...

  8. HTML 基本概念梳理——涉及HTML简要发展史、基本标签

    本文原产于个人有道云笔记,迁移CSDN时部分图片未上传,格式未调整.望阅读的人海量. 1.HTML基础--基本概念 1.1什么是浏览器 浏览器是安装在电脑里面的一个软件, 能够将网页内容呈现给用户查看 ...

  9. 【NLP】万字梳理!BERT之后,NLP预训练模型发展史

    作者 | 周俊贤 整理 | NewBeeNLP 本文讲解下BERT推出后,预训练模型的演变,包括BERT.RoBERTa.ALBERT.ERNIE系列.ELECTRA.下面脑图是本系列第一篇内容,欢迎 ...

最新文章

  1. thymeleaf+layui加载页面渲染时,TemplateProcessingException: Could not parse as expression:
  2. pack_padded_sequence 和 pad_packed_sequence
  3. mysql cte 表不存在_使用CTE解决复杂查询的问题_MySQL
  4. 史上最实用mysql参数之一-----sql_safe_updates
  5. 北大、清华计算机课程资源集
  6. Jmeter4.0---- HTTP请求默认值(14)
  7. js学习总结----浏览器滚动条卷去的高度scrolltop
  8. 无线局域网打印服务器,无线局域网环境下怎么连接网络打印机
  9. 在iphone中添加日历库kal
  10. 关于Blurry无法加载的问题
  11. 安卓手机如何投屏到电脑--直播 反控 玩游戏
  12. 2014热门网络词汇汇总
  13. 第五项修炼--学习型组织的艺术与实践
  14. Oracle 收缩表空间一例
  15. 云计算、大数据以及物联网的区别和联系
  16. php通过ftp上传文件
  17. SMT贴片打样中常出现“立碑”的原因有哪些?
  18. Candy UVA 1639 (数学期望)
  19. LoLSkip2.0使用说明(英雄联盟换肤全皮肤版本)
  20. 对话快手 | 如何从0到1建立商业化品牌的海外影响力?

热门文章

  1. 菜鸟学Java——简单验证码生成(Java版)
  2. 2000-2017年全球人口密度数据下载LandScan
  3. 华为ensp---AC三层旁挂组网实验(参照华为官方手册)
  4. pip版本更新的问题
  5. linux下不让使用rm命令
  6. CSS 重要属性与定位
  7. 51SCM_AD模块CS5550学习心得
  8. MySQL多表查询优化
  9. 黑马程序员-java-String
  10. idea远程断点调试