You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

139 lines
11 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 01 | 元字符:如何巧妙记忆正则表达式的基本元件?
你好,我是涂伟忠。今天是课程的第一讲,我们一起来学习组成正则表达式的基本单元——元字符。
## 元字符的概念
在开篇词中,我们提到了正则常见的三种功能,它们分别是:校验数据的有效性、查找符合要求的文本以及对文本进行切割和替换等操作。
![](https://static001.geekbang.org/resource/image/54/1b/54a184548d369ca04ad4b69cd15dac1b.png)
那你可能会好奇,正则是如何完成这些工作的呢?让我们先从简单的字符串查找和替换讲起。
我相信你一定在办公软件比如Word、Excel 中用过这个功能。你可以使用查找功能快速定位关注的内容,然后使用替换,批量更改这些内容。
![](https://static001.geekbang.org/resource/image/68/33/682df773ff276084ca4f934af53fa233.png)
让我们再回过头看看正则表达式。正则表达式,简单地说就是描述字符串的规则。在正则中,普通字符表示的还是原来的意思,比如字符 a它可以匹配“Hanmeimei is a girl”中的 H 之后的 a也可以匹配 is 之后的 a这个和我们日常见到的普通的字符串查找是一样的。
![](https://static001.geekbang.org/resource/image/c5/f6/c54ddfaa8a56453afed49f31022a8df6.png)
但除此之外,正则还可以做到普通的查找替换做不到的功能,**它真正的****强大之处****就在于可以查找符合某个规则的文本**。
举个例子假如你想查找文本中的所有数字如果不会正则可能需要手动敲数字从0到9这样操作10次一个个去查找很麻烦。但如果用正则的话就方便很多了我们直接使用 **\\d** 就可以表示 0-9 这10个数字中的任意一个如下图所示。
![](https://static001.geekbang.org/resource/image/3a/ab/3af8dd848b2d625db7831aa8adcd6fab.png)
如果我们在后面再加上量词,就可以表示单个的数字出现了几次。比如 \\d{11} 表示单个数字出现11次即11位数字如果文本中只有姓名和手机号我们就可以利用这个查找出文本中的手机号了如下图所示。
![](https://static001.geekbang.org/resource/image/5a/bd/5a0ce54804cc08eb3622f418c3af45bd.png)
那么到这里,你有没有发现正则的不同呢?像查找数字一样,在正则中,我们不需要像往常一样输入一个确定的内容,只需要敲入特殊的符号就可以帮我们完成查找和替换,像上面案例中提到的 \\d 和 {11}在正则中有一个专门的名称——元字符Metacharacter
**所谓元字符就是指那些在正则表达式中具有特殊意义的专用字符**,元字符是构成正则表达式的基本元件。正则就是由一系列的元字符组成的,看到这里相信你也能明白元字符的重要性了吧。
但是,因为元字符很基础,又比较多,所以很多人看见正则就头疼。那么今天,我就通过分类的方式,教你理解并且巧妙地记忆、使用元字符。
## 元字符的分类与记忆技巧
正则表达式中有很多的“元字符”,比如刚刚提到的 \\d它在正则中不代表 \\ (反斜杠) 加字母 d而是代表任意数字这种表示特殊含义的字符表示就是元字符。正则表达式中元字符非常多那么我们如何才能记住它们呢
这里我给你介绍一个方法,就是分类记忆。元字符虽然非常多,但如果我们按照分类法去理解记忆,效果会好很多。事实上,这个方法不光可以用在记忆元字符上,也可以用在记忆各种看似没有章法的内容上。
首先我可以把元字符大致分成这几类表示单个特殊字符的表示空白符的表示某个范围的表示次数的量词另外还有表示断言的我们可以把它理解成边界限定我会在后面的章节中专门讲解断言Assertions相关的内容。
![](https://static001.geekbang.org/resource/image/97/bb/97f9aa05196ecba15a433e6e517093bb.png)
那么接下来,我们就按照前面说的元字符的分类,来逐一讲解下。
### 1.特殊单字符
首先,我们来看下表示特殊单个字符的元字符,比如英文的点(.)表示换行以外的任意单个字符,\\d 表示任意单个数字,\\w 表示任意单个数字或字母或下划线,\\s 表示任意单个空白符。另外,还有与之对应的三个 \\D、\\W 和 \\S分别表示着和原来相反的意思。
![](https://static001.geekbang.org/resource/image/19/4b/199562249878c0967dde9f23c0b4904b.png)
现在我们来看一下测试,我把常见数字,字母,部分标点符号作为文本,用 \\d 去查找可以看到只能匹配上10个数字。
![](https://static001.geekbang.org/resource/image/13/a5/1380b43ba8a8ebf4a307a5d0a4e35aa5.png)
这是元字符 **\\d** 测试用例的链接,你不妨测试一下:[https://regex101.com/r/PnzZ4k/1](https://regex101.com/r/PnzZ4k/1)
元字符 \\w 能匹配所有的数字、字母和下划线,如下图所示:
![](https://static001.geekbang.org/resource/image/60/f1/60041ca73688567b0bae04950f8be0f1.png)
同样的,元字符 **\\w** 测试用在这里:[https://regex101.com/r/PnzZ4k/2](https://regex101.com/r/PnzZ4k/2)
你可以自己去尝试一下 \\W\\D\\s 和 \\S ,以及英文的点的匹配情况,这里我不展开了。
### 2.空白符
除了特殊单字符外,你在处理文本的时候肯定还会遇到空格、换行等空白符。其实在写代码的时候也会经常用到,换行符 **\\n**TAB制表符 **\\t** 等。
有编程经验的程序员肯定都知道不同的系统在每行文本结束位置默认的“换行”会有区别。比如在Windows 里是 **\\r\\n**,在 Linux 和 MacOS 中是 **\\n**。
在正则中,也是类似于 \\n 或 \\r 等方式来表示空白符号,只要记住它们就行了。平时使用正则,大部分场景使用 \\s 就可以满足需求,\\s 代表任意单个空白符号。
![](https://static001.geekbang.org/resource/image/01/66/01b6c8de6ee6c440471c15f96d00d466.png)
我们可以看到, **\\s** 能匹配上各种空白符号,也可以匹配上空格。换行有专门的表示方式,在正则中,空格就是用普通的字符英文的空格来表示。
### 3.量词
刚刚我们说到的“基础”的元字符也好,“空白符”也好,它们都只能匹配单个字符,比如\\d只能匹配一个数字。但更多时候我们需要匹配单个字符或者某个部分“重复N次”“至少出现一次”“最多出现三次”等等这样的字符这个时候该怎么办呢
这就需要用到表示量词的元字符了。
在正则中,英文的星号(\*代表出现0到多次加号+代表1到多次问号?代表0到1次{m,n}代表m到n次。
![](https://static001.geekbang.org/resource/image/2b/c3/2b03098dcc203c648a40f89a0ba77fc3.png)
比如,在文本中“颜色”这个单词,可能是带有 u 的 colour也可能是不带 u 的 color我们使用 colou?r 就可以表示两种情况了。在真实的业务场景中比如某个日志需要添加了一个user字段但在旧日志中这个是没有的那么这时候可以使用问号来表示出现0次或1次这样就可以表示user字段**存在和不存在**两种情况。
下面这段文本由三行数字组成,当我们使用 \\d+ 时能匹配上3个但使用 \\d\* 时能匹配上6个详细匹配结果可以参考下面的图片
![](https://static001.geekbang.org/resource/image/f0/4e/f0696d3fbc55c5a75832472e227a614e.png)
我把正则 \\d+ 示例链接放在下面了,你可以看一下:[https://regex101.com/r/PnzZ4k/8](https://regex101.com/r/PnzZ4k/8)
其它的比如表示 m 到 n 次的,你可以自己去尝试,一定要多加练习,这样你才能记得牢。
### 4.范围
学习了量词,我们就可以用 \\d{11} 去匹配所有手机号但同时也要明白这个范围比较大有一些不是手机号的数字也会被匹配上比如11个0那么我们就需要在一个特殊的范围里找符合要求的数字。
再比如我们要找出所有元音字母aeiou的个数这又要如何实现呢在正则表达式中表示范围的元字符可以轻松帮我们搞定这样的问题。
在正则表达式中,表示范围的符号有四个分类,如下图所示。
![](https://static001.geekbang.org/resource/image/84/22/84625cc80a90dba2c629282e3f213622.png)
首先是管道符号,我们用它来隔开多个正则,表示满足其中任意一个就行,比如 **ab|bc** 能匹配上 ab也能匹配上 bc在正则有多种情况时这个非常有用。
中括号\[\]代表多选一,可以表示里面的任意单个字符,所以任意元音字母可以用 **\[aeiou\]** 来表示。另外,中括号中,我们还可以用中划线表示范围,比如 **\[a-z\]** 可以表示所有小写字母。如果中括号第一个是脱字符(^),那么就表示非,表达的是不能是里面的任何单个元素。
比如某个资源可能以 http:// 开头,或者 https:// 开头,也可能以 ftp:// 开头,那么资源的协议部分,我们可以使用 (https?|ftp):// 来表示。
![](https://static001.geekbang.org/resource/image/22/3d/22b3ef8c95b01adddebad77fed106a3d.png)
同样地,我把示例链接也放在了下面,你可以参考一下:[https://regex101.com/r/PnzZ4k/5](https://regex101.com/r/PnzZ4k/5)
## 总结
今天我通过大量的示例讲解了元字符,希望可以帮助你加强对正则各类元字符的理解,想办法记住它们,这是掌握正则这个强大工具的第一步。
我在这里给你强调一下学习的方法。你可以看到我在每一个案例中加入了测试链接,目的就是希望你能借此多做练习。在学习过程中,一定要找时间去练习,去观察匹配的结果,这样可以帮助你加深记忆。如果只是看和听,没有足够的练习,实际上很难记得牢,所以一定要自己多动手操作尝试。
还有一个方法,你可以把学到的知识,试着讲给其它的同事或同学,最好的学习方法就是去教别人,一个知识点,如果你能给别人讲明白,证明你真的搞懂了,真的掌握了这个知识。
好了,学习完今天的内容,最后我来给你总结一下。正则表达式中元字符的分类记忆,你可以在脑海中回忆一下。今天我们学习了正则表达式的部分元字符,特殊单字符、空白符、范围、量词等。我整理成了一张脑图,你可以看一下,对照着练习、记忆。
![](https://static001.geekbang.org/resource/image/ff/52/ffd9cd49a79599e7efa4aba069faee52.png)
## 思考题
通过今天的学习,不知道你元字符掌握到何种程度了呢?那么不妨练习一下吧!我在这里给出一些手机号的组成规则:
1. 第1位固定为数字1
2. 第2位可能是3456789
3. 第3位到第11位我们认为可能是0-9任意数字。
你能不能利用今天学到的知识,写出一个“更严谨”的正则来表示手机号呢?
好,今天的课程就结束了,希望可以帮助到你,也希望你在下方的留言区和我参与讨论,让我们一起进步,共同掌握正则表达式这个强大的工具。