一直感觉正则表达式很神奇,非常强大,但并没有系统学习过,今天抽空过一遍,希望能够彻底掌握它
简介
正则表达式在处理文本信息时非常有用,不限于代码、日志文件、文档等。在开始学习正则之前,需要有这种概念:任何文本都是由单个字符组成。
语法
简单匹配
abcdefg、abcde、abc这三个字符串,用正则abc可以匹配前面三个串的abc字段
abc123xyz、define”123”、var g=123,用正则123可以匹配三个公共的123数字
简单语法
\d 匹配任何0~9的数字;\D匹配任意非数字0~9的字符
.表示通配符,可以匹配任意字符。如果要匹配.,可以加入转义符\.
| Task | Text |
|---|---|
| Match | cat. |
| Match | 896. |
| Match | ?=+. |
| Skip | abc1 |
上面的例子,正则...\.匹配前三个,最后一个不匹配
匹配特定的字符,使用[]
| Task | Text |
|---|---|
| Match | can |
| Match | man |
| Match | fan |
| Skip | dan |
| Skip | ran |
| Skip | pan |
上面的例子,需要匹配前三个,后三个不匹配,可用正则[cmf]an。[cmf]表示只匹配cmf之中的任意一个。
剔除特定字符,使用[^…]
| Task | Text |
|---|---|
| Match | hog |
| Match | dog |
| Skip | bog |
上面的例子,需要匹配前练个,最后一个不匹配,可用正则[^b]og,当然也可以用前面的匹配特定字符[hd]og
连续字符,使用-
如果要匹配26个小写字母,难道我们要吧26个字母全部列出来么?当然可以,但太二了不是么。正则表达式用-表示连续的字符。如0-6相当于[0123456]
| Task | Text |
|---|---|
| Match | Ana |
| Match | Bob |
| Match | Cpc |
| Skip | aax |
| Skip | bby |
| Skip | ccz |
上面的例子,匹配前三个,后三个不匹配,可用正则[A-c][n-p][a-c]
注意,大写和小写字母是不同的字符,需要分开处理
\w相当于[A-Za-z0-9_],\W相当于[^A-Za-z0-9_]
字符个数的匹配,使用{}
前面提到的额匹配都是单个字符的匹配,如果需要匹配3个数字,你也许会写成\d\d\d,但实际上有更好的写法,比如\d{3}。正则甚至支持范围,如a{1,3}表示最少有1个a,最多3个a。
| Task | Text |
|---|---|
| Match | wazzzzzup |
| Match | wazzzup |
| Skip | wazup |
上面的例子,前两个匹配,最后一个不匹配,可用正则表达式waz{3,5}up
字符任意个数的匹配
*表示大于等于0个
+表示大于等于1个
比如,\d*表示任意个数字,但是\d+则表示最少要有一个数字
| Task | Text |
|---|---|
| Match | aaaabcc |
| Match | aabbbbc |
| Match | aacc |
| Skip | a |
上面的例子,前三个匹配,最后一个不匹配,可用正则aa+b*c+
标记某个字符可选,使用?
由于?修饰的字符为可选,所以正则ab?c可以匹配abc或者ac。
| Task | Text |
|---|---|
| Match | 1 file found? |
| Match | 2 files found? |
| Match | 24 files found? |
| Skip | No files found. |
上面的例子,前三个匹配,最后一个不匹配,可用正则\d+ files? found\?
空格、换行、对齐等字符
空格 制表符tab(\t) 换行(\n) 回车(\r)。可以用\s来表示前面任意的空白符。同理,\S与\s相反,即各种空白符之外的字符。
| Task | Text |
|---|---|
| Match | 1. abc |
| Match | 2. abc |
| Match | 3. abc |
| Skip | 4.abc |
上面的例子,前三个匹配,最后一个不匹配,可用正则\d\.\s+abc
开始^和结束$
需要注意的是,这里的开始^和例外[^...]的意义是不同的。假如需要验证用户的输入是否为5-12位数字组成的QQ号码,可以用^\d{5,12}$。
| Task | Text |
|---|---|
| Match | Mission: successful |
| Skip | Last Mission: unsuccessful |
| Skip | Next Mission: successful upon capture of target |
上面的例子,第一个匹配,后两个不匹配,可用正则^Mission: successful$
匹配并分组(…)
正则表达式不仅仅可以用来匹配,还可以将匹配的结果进行分组group。
比如,我们可以用正则表达式^(IMG\d+\.png)$找出所有照片,但是如果我们只需要照片名,不需要后缀名png呢,你会怎么做?这个时候可以用^(IMG\d+)\.png$
| Task | Text |
|---|---|
| Capture | file_record_transcript.pdf |
| Capture | file_07241999.pdf |
| Skip | testfile_fake.pdf.tmp |
上面的例子,可用正则^(file.+)\.pdf$
当然,分组还支持嵌套,用于更复杂的多重分组。如下,匹配日期并且列出年份
| Task | Text |
|---|---|
| Capture | Jan 1987 |
| Capture | May 1969 |
| Capture | Aug 2011 |
上面的例子,可用正则(\w+ (\d{4}))
条件匹配(…|…)
假如你让别人给你带早餐,但你又不确定早餐店还剩下什么,这时候你会给别人几个备选项,在正则里可以用(..|..)来表示。如Buy more (milk|bread|juice)
| Task | Text |
|---|---|
| Match | I love cats |
| Match | I love dogs |
| Skip | I love logs |
| Skip | I love cogs |
上面的例子,可用正则I love (cats|dogs)
字符边界
通常用\b表示字符的边界,与之相对的\B。现有字符串Chapter 1,可以用正则ter\b匹配得到ter,注意\b的位置,如果正则写成\bter则无匹配结果
练习
匹配浮点数
| Task | Text |
|---|---|
| Match | 3.14529 |
| Match | -255.34 |
| Match | 128 |
| Match | 1.9e10 |
| Match | 123,340.00 |
| Skip | 720p |
上面的例子,可用正则表达式^-?\d+(,\d+)*(\.\d+(e\d+)?)?$
匹配图片
| Task | Text |
|---|---|
| Skip | .bash_profile |
| Skip | workspace.doc |
| Capture | img0912.jpg |
| Capture | updated_img0912.png |
| Skip | documentation.html |
| Capture | favicon.gif |
| Skip | img0912.jpg.tmp |
| Skip | access.lock |
上面的例子,可用正则表达式(\w+)\.(jpg|png|gif)$
说明
本文参考链接regexone
文中的正则表达式只是示例,要达到同样的结果,正则表达式可能有多种写法