理解正则表达式

发布于 2022-03-06 19:15:31 字数 3646 浏览 1202 评论 0

在我初学正则表达式的时候,走了一些弯路,强行记忆了很多符号和用法。

等到我有更深入的理解的时候我发现,从翻译和概念的角度上切入,学习起来会顺畅得多。

本文以JavaScript里的正则表达式为例,讲解其中的关键要素。希望能帮助到初学者。

注:也只限于阐述关键要素,不会事无巨细地展开。

何为正则表达式?

在中文语境里,「正则」两个字有点让人发怵,仿佛高深数学或物理中的「正则化」和「归一化」,抽象而难懂。

其实放到英文里,它是regular expression,而regular有「规律、规范、整齐、合格、正规」等意味,「正则」只是其中一种翻译。

不把它翻译成一个词组,而翻译成一句话,大致是:表达规范和规则的句子。

这里的规范和规则,指的是一个字符串的形式规则。

至于JavaScript里的 RegExp 构造函数,是Regular Expression的前三个字母缩写。

正则表达式的格式

JavaScript里,正则表达式有两个构造方式,一个是通过RegExp这个构造函数创建实例,另一个是正则表达式字面量写法。

var regexp1 = new RegExp('hello regular expression')
var regexp2 = /hello regular expression/

// test 方法,测试给定的字符串是否符合正则表达式所描述的字符串格式
regexp1.test('hello regular expression') // -> true
regexp1.test('hello word') // -> false

// exec 方法,是 execute 这个单词的缩写,「执行」。返回给定的字符串中符合「正则表达式所描述的字符串格式」的部分
regexp2.exec('hello regular expression') //  返回 'hello regular expression'
regexp2.exec('hello regular expression, more words') //  只返回 'hello regular expression',其它部分不匹配

正则表达式里的元字符

元字符听起来也很抽象,其实换个例子就容易理解:学习如何学习,叫元学习;关于知识的知识,叫元知识。

元字符,则是描述字符的字符,比如,数字,字母,空格,换行等。

元编程,就是能生成代码的代码,在 Javascript 构造符合语法的字符串,放到eval(code)里运行一下,你就在元编程了。

然后看看元字符、元编程的英文:meta-charactermeta-programming,对 meta 长个记性,怯魅。

列举几个元字符。元字符大多以反斜杠开头 \,因为前面展示的「正则表达式字面量」写法里,用的是两个斜杠包裹,所以得用反斜杠或其他标识符。

  • \d,匹配单个数字;d 是 digit 这个单词的缩写,它的中文意思就是「数字」
  • \w,匹配单个单词字符,w 是 word 的缩写,就是字母 a-z,数字 0-9,不包括逗号、句号、加减乘除号、括号等。
  • \s,匹配单个空白字符,s 是 space 的缩写,就是空白的意思。
  • \n,匹配换行符,n 是 newline 的缩写,中文就是换行。
  • \r,匹配回车符,r 就是 return 的缩写,回车在这里就是它的中文意思。
  • \t,匹配制表符,就是 tab 键打出来的一串用以缩进的空白字符,tab 是 tabel 的缩写,table 就有表格和制表的意思。
  • \b,匹配单词边界,b 是 boundary 的缩写,中文就是边界的意思。

如你所见,所谓的元字符,就是反斜杠加单词缩写,来表征某个字符类型。这就是它们的设计原则。

正则表达式里的量词

元字符大多只能表示单个字符的类型。

我们还需要量词,以表示「有,有0到多个,有至少一个,有n个以上,有n到m个,以某个字符开头,以某个字符结尾等」。

这时你可以停下来,稍作思考,让你来设计,你会设计成什么样?

Javascript的设计如下:

  • n+,至少1个 n 类型的字符
  • n*,0到多个 n 类型的字符
  • n?,0 或 1 个 n 类型的字符
  • n{X},X 个 n 类型的字符
  • n{X,Y},X 到 Y 个 n 类型的字符
  • n{X,},至少 X 个 n 类型的字符
  • n$,以 n 类型的字符结尾
  • ^n,以 n 类型的字符开头

如你所见,大致是一些类似数学里表达区间的意思。

正则表达式里的表达式

你可以戏谑地说它是「元表达式」。

其实,它们也是描述范围的,只是不是所有范围都是关于某个字符类型n 的数量和出现位置,有些范围跟多个字符组成的集合有关。

比如,在这几个字符类型之内,在这几个字符类型之外的,便利地表示 26 个字母,便利地表示 10 个数字字符。

Javascript的设计如下:

  • [abc],匹配单个字符,它是abc的集合的元素
  • [^abc],匹配单个字符,它不是abc的集合的元素
  • [0-9],匹配单个字符,它是从0到9这个集合的元素
  • [a-z],匹配单个字符,它是26 字母这个集合的元素
  • (red|blue|green),匹配多个连续字符,它是 red blue green 这三个词的集合的元素

小试牛刀

匹配一个电话号码,形式如 020-88813243。

简单版本,(开头)三个数字+一个横杠+八个数字(结尾),就是/^\d{3}-\d{8}$/

需求变化,只匹配 020 开头的电话号码,就是/^020-\d{8}$/

需求变化,支持分机,分机为 5 个数字,加后缀,就是/^020-\d{8}-\d{5}$/

需求变化,电话号码可以是7个,用区间量词,就是/^020-\d{7,8}-\d{5}$/

需求变化,有可能没有分机,用区间量词,中括号包裹住分机为一组,后面加个问号,表示0或多个,就是/^020-\d{7,8}(-\d{5})?$/

需求变化,区隔符可能是横杠,也可能是星号或空格,用集合表达式,就是/^020[-*\s]\d{7,8}([-*\s]\d{5})?$/

结语

在我们理解了正则表达式的概念和设计思路之后,剩下的,就是查文档和寻找模式的工作了。

实在有难题,网上也可以搜索到现成的坚实的正则表达式可用。这里面的门道还是很多的,在此我们入个门,打个基础即可。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84961 人气
更多

推荐作者

醉城メ夜风

文章 0 评论 0

远昼

文章 0 评论 0

平生欢

文章 0 评论 0

微凉

文章 0 评论 0

Honwey

文章 0 评论 0

qq_ikhFfg

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文