方法归纳
方法 | 描述 |
---|---|
findall | 将字符串中所有的非重叠匹配模式以列表形式返回 |
finditer | 与findall类似,但返回的是迭代器 |
match | 在字符串起始位置匹配模式,也可以将模式组件匹配到分组中; 如果模式匹配上了,返回一个匹配对象,否则返回None |
search | 扫描字符串的匹配模式,如果扫面到了返回匹配对象; 与match方法不同的是,search方法的匹配可以是字符串的任意位置, 而不仅仅是字符串的起始位置 |
split | 根据模式,将字符串拆分为多个部分 |
sub,subn | 用替换表达式替换字符串中所有的匹配(sub)或第n个出现的匹配串(subn); 使用符号\1,\2....来引用替换字符串中匹配组的元素 |
compile
正则表达式提供了一种在文本中灵活查找或匹配字符串模式的方法。单个表达式通常被称为regex,是根据正则表达式语言形成的字符串。Python内建的re模块是用于将正则表达式应用到字符串上的库。接下来展示一些re模块的实例。
re模块主要有三个主题:模式匹配、替代、拆分。当然,这三个主题是相关联的。一个正则表达式描述了在文本中需要定位的一种模式,可以用于多种目标。
让我们来看一个简单的示例:假设我们想将含有多种空白字符(制表符、空格、换行符)的字符串拆分开。描述一个或多个空白字符的正则表达式是\s+:
import re
text = "foo bar\t baz \tqux"
re.split('\s+', text)
当调用re.split('\s+', text)时,正则表达式首先会被编译,然后正则表达式的split方法在传入文本上被调用。也可以使用re.compile自行编译,形成一个可复用的正则表达式对象。
regex = re.compile('\s+')
regex.split(text)
以上两段执行结果相同:
['foo', 'bar', 'baz', 'qux']
findall
如果需要获得的是一个所有匹配正则表达式的模式的列表,你可以使用findall方法:
regex.findall(text)
//out: [' ', '\t ', ' \t']
PS:为了在正则表达式中避免转义符\的影响,可以使用原生字符串语法,比如 r'C:\x' 或者用等价的 'C:\x'
如果需要将相同的表达式应用在多个字符串上,推荐使用re.compile创建一个正则表达式对象,这样做有利于节约CPU周期。
search、match
match和search与findall相关性很大。findall返回的是字符串中所有的匹配项,而search返回的仅仅是第一个匹配项。match更为严格,它只在字符串的起始位置进行匹配。我们来看下一个示例,一段文本和一个可以识别大部分电子邮件地址的正则表达式:
在文本上使用findall会生成一个电子邮件地址的列表:
text = '''Dava dava@google.com
Steve steve@gmail.com
Rob rob@gmail.com
Ryan ryan@yahoo.com
'''
pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'
# re.IGNORECASE 使正则表达式不区分大小写
regex = re.compile(pattern, flags=re.IGNORECASE)
regex.findall(text)
//out: ['dava@google.com', 'steve@gmail.com', 'rob@gmail.com', 'ryan@yahoo.com']
search返回的是文本中第一个匹配到的电子邮件地址。对于前面提到的正则表达式,匹配对象只能告诉我们模式在字符串中起始和结束的位置:
m = regex.search(text)
m
//out: <re.Match object; span=(5, 20), match='dava@google.com'>
text[m.start():m.end()]
//out: 'dava@google.com'
regex.match只在模式出现于字符串起始位置时进行匹配,如果没有匹配到,返回None:
print(regex.match(text))
//out: None
sub
sub会返回一个新的字符串,原字符串中的模式会被一个新的字符串替代:
s = regex.sub('REDACTED',text)
print(s)
//out: Dava REDACTED
Steve REDACTED
Rob REDACTED
Ryan REDACTED
扩展
假设想查找电子邮件地址,并将每个地址分为三个部分:用户名、域名和域名后缀。要实现这一点,可以用括号将模式包起来。由下面修改后的正则表达式产生的匹配对象的groups方法,返回的是模式组件的元组:
pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'
regex = re.compile(pattern, flags = re.IGNORECASE)
m = regex.match('wesm@bright.net')
m.groups()
//out: ('wesm', 'bright', 'net')
当模式可以分组时,findall返回的是包含元组的列表:
regex.findall(text)
//out: [('dava', 'google', 'com'),
('steve', 'gmail', 'com'),
('rob', 'gmail', 'com'),
('ryan', 'yahoo', 'com')]
sub也可以使用特殊符号,如\1和\2,访问每个匹配对象中的分组。符号\1代表的是第一个匹配分组,\2代表的是第二个匹配分组,以此类推:
L = regex.sub(r'Username: \1, Domain: \2, Suffix: \3', text)
print(L)
//out: Dava Username: dava, Domain: google, Suffix: com
Steve Username: steve, Domain: gmail, Suffix: com
Rob Username: rob, Domain: gmail, Suffix: com
Ryan Username: ryan, Domain: yahoo, Suffix: com
去掉\3,便于理解
L = regex.sub(r'Username: \1, Domain: \2, Suffix: ', text)
print(L)
//out:Dava Username: dava, Domain: google, Suffix:
Steve Username: steve, Domain: gmail, Suffix:
Rob Username: rob, Domain: gmail, Suffix:
Ryan Username: ryan, Domain: yahoo, Suffix:
网友评论