跟风学正则の笔记 测试工具

what is Regular Expression

正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。

How

From LiaoXueFeng

Simple Introduction

在正则表达式中,如果直接给出字符,就是精确匹配。

\d可以匹配一个数字,\w可以匹配一个字母或数字,所以:

  • '00\d'可以匹配'007',但无法匹配'00A'

.可以匹配任意字符,所以:

  • 'py.'可以匹配'pyc''pyo''py!'

要匹配变长的字符,在正则表达式中,

  1. *表示任意个字符(包括0个)
  2. +表示至少一个字符
  3. ?表示0个或1个字符
  4. {n}表示n个字符,用{n,m}表示n-m个字符:

A|B可以匹配A或B,所以(P|p)ython可以匹配'Python'或者'python'

^表示行的开头,^\d表示必须以数字开头。

$表示行的结束,\d$表示必须以数字结束。

如果你想查找元字符本身的话,比如你查找.,或者,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此,你应该使用.和\。当然,要查找\本身,你也得用\.

例如:deerchao\.net匹配deerchao.net,C:\\Windows匹配C:\Windows。

In Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import re
# 从头找,找到了返回对象,找不到返回none
re.match(p,text)
# 不是从第一个字符开始找
obj = re.search(p,text)
obj.start(),obj.end(),obj.group()

# 找到多个对象
re.findall(p,text)
# 找到后把字符串分隔开
re.split(p,text)
# p替换成s
re.sub(p,s,text)

^ 字符串开头
\b 单词开头\末尾
\w 数字字母
\S 不是空格
+ == {1,}
? 非贪婪模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import re

s = r'ABC\-001'

ans = re.match(r'^\d{3}\-\d{3,8}$', '010-12345')
# <_sre.SRE_Match object; span=(0, 9), match='010-12345'>
# print(ans.group(0)

ans = re.match(r'^\d{3}\-\d{3,8}$', '010 12345')
#none

re.split(r'\s+', 'a b c')
# +匹配前面的子表达式一次或多次
# \s匹配任何空白字符
# ['a', 'b', 'c']

ans = re.split(r'[\s\,]+', 'a,b, c d')
# \将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符
# ['a', 'b', 'c', 'd']

# 分组
m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
# <_sre.SRE_Match object; span=(0, 9), match='010-12345'>
m.group(0)
# '010-12345'
m.group(1)
# '010'
m.group(2)
# '12345'

# 贪婪匹配
re.match(r'^(\d+)(0*)$', '102300').groups()
# + 匹配前面的子表达式一次或多次。
# * 匹配前面的子表达式零次或多次
# ('102300', '')
# 非贪婪匹配
re.match(r'^(\d+?)(0*)$', '102300').groups()
#? 匹配前面的子表达式零次或一次。
#('1023', '00')

print(ans)

#预编译
# 编译:
re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$')
# 使用:
re_telephone.match('010-12345').groups()
#('010', '12345')

字符类型

  1. 普通字符

  2. 非打印字符

    | char | description |
    | —- | ———————————- |
    | \cx | 匹配由x指明的控制字符。 |
    | \f | 匹配一个换页符。等价于 \x0c 和 \cL |
    | \n | 匹配一个换行符。等价于 \x0a 和 \cJ |
    | \r | 匹配一个回车符。等价于 \x0d 和 \cM |
    | \s | 匹配任何空白字符 空格、制表符、换页符==[\f\n\r\t\v]。 |
    | \S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |

  3. 控制字符

    | char | description |
    | —- | —————————————- |
    | $ | 匹配输入字符串的结尾位置。 |
    | ( ) | 标记一个子表达式的开始和结束位置。 |
    | | 匹配前面的子表达式零次或多次。要匹配 字符,请使用 *。 |
    | + | 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 +。 |
    | . | 匹配除换行符 \n之外的任何单字符。要匹配 .,请使用 \。 |
    | [ | 标记一个中括号表达式的开始。要匹配 [,请使用 [。 |
    | ? | 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。 |
    |  | 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n’ 匹配字符 ‘n’。’\n’ 匹配换行符。序列 ‘\‘ 匹配 “\”,而 ‘(‘ 则匹配 “(“。 |
    | ^ | 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。 |
    | { | 标记限定符表达式的开始。要匹配 {,请使用 {。 |
    | | | 指明两项之间的一个选择。要匹配 |,请使用 |。 |
    | | |

  4. 限定字符

char description
* 匹配前面的子表达式零次或多次。例如,zo 能匹配 “z” 以及 “zoo”。 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,’zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,”do(es)?” 可以匹配 “do” 或 “does” 中的”do” 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,’o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,’o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。’o{1,}’ 等价于 ‘o+’。’o{0,}’ 则等价于 ‘o*’。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,”o{1,3}” 将匹配 “fooooood” 中的前三个 o。’o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。

示例

\d{3}\s+\d{3,8}

  1. \d{3}表示匹配3个数字,例如'010'
  2. \s可以匹配一个空格(也包括Tab等空白符),所以\s+表示至少有一个空格,例如匹配' '' '等;
  3. \d{3,8}表示3-8个数字,例如'1234567'

\(?0\d{2}[) -]?\d{8}。

“(”和“)”也是元字符,后面的分组节里会提到,所以在这里需要使用转义

这个表达式可以匹配几种格式的电话号码,像(010)88886666,或022-22334455,或02912345678等。我们对它进行一些分析吧:首先是一个转义字符(,它能出现0次或1次(?),然后是一个0,后面跟着2个数字(\d{2}),然后是)或-或空格中的一个,它出现1次或不出现(?),最后是8个数字(\d{8})。

正则表达式 描述
/\b([a-z]+) \1\b/gi 一个单词连续出现的位置。
/(\w+):\/\/([^/:]+)(:\d)?([^# ])/ 将一个URL解析为协议、域、端口及相对路径。
/^(?:Chapter\ Section) [1-9][0-9]{0,1}$/ 定位章节的位置。
/[-a-z]/ A至z共26个字母再加一个-号。
/ter\b/ 可匹配chapter,而不能匹配terminal。
/\Bapt/ 可匹配chapter,而不能匹配aptitude。
/Windows(?=95 \ 98 \ NT )/ 可匹配Windows95或Windows98或WindowsNT,当找到一个匹配后,从Windows后面开始进行下一次的检索匹配。
/^\s*$/ 匹配空行。
/\d{2}-\d{5}/ 验证由两位数字、一个连字符再加 5 位数字组成的 ID 号。
/<\s(\S+)(\s[^>])?>[\s\S]<\s\/\1\s*>/ 匹配 HTML 标记。

Exercise

email

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import re
# email

patten = 'bill.gates@microsoft.com'
r = r'^(\w*)\.?(\w*)@(\w+).(\w+)'

print(re.match(r,patten).groups())

r1 = r'(<\w+\s\w+>)\s*(\w*)\.?(\w*)@(\w+).(\w+)'
patten1 = '<Tom Paris> tom@voyager.org'
print(re.match(r1,patten).groups())

# 别人的
re_email = re.match(r'^(\w+\.\w+|\w+)(\@\w+\.com)$','bill.a@microsoft.com')
print(re_email.groups())

参考资料

Runoob 30min 廖雪峰 官方文档 python正则 路人甲