正则表达式

正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。

 

1. 正则表达式模式

   模式,是正则表达式最基本的元素,它们是一组描述字符串特征的字符。模式可以很简单,由普通的字符串组成,也可以非常复杂,

   往往用特殊的字符表示一个范围内的字符、重复出现,或表示上下文。

^         # 匹配字符串的开始, 如^The, 可以匹配The开头的字符串
$         # 匹配字符串的结束, 如.exe$, 可以匹配.exe结尾的字符串
[]        # 匹配来自字符集的任意单一字符, 如[aeiou]可以匹配任一元音字母字符; [a-z]匹配 a-z 之间的任意一个小写字母; [a-zA-Z]则会匹配任意一个字母 
[^]       # 匹配不在字符集中的任意单一字符, 如[^aeiou]可以匹配任一非元音字母字符; [^a-z]匹配任意不在 a-z 范围内的任意一个字母
\w        # 匹配一个数字或字母或下划线
\W        # 匹配一个不是字母、数字和下划线的字符
\s        # 匹配任意空白字符,包括空格、制表符、换行符
\S        # 匹配任意非空白字符
\d        # 匹配一个数字
\D        # 匹配非数字
\t        # 匹配一个制表符
\n        # 匹配一个换行符
\r        # 匹配一个回车符
*         # 匹配前面的子表达式任意次,即0次或多次
+         # 匹配前面的子表达式一次或多次
?         # 匹配前面的子表达式零次或一次,等价于{0,1}
.         # 匹配除 \n 和 \r 之外的任何单个字符
{N}       # n是一个非负整数。匹配确定的n次
{M,}      # 匹配至少M次, 如\w{3,}
{M,N}     # 匹配至少M次至多N次, 如\w{3,6}
|         # 分支, 如foo|bar, 可以匹配foo或者bar

# 以下是一些组合的模式,具有组合的意义,不能按单个来理解
.*        # .代表任一个字符,*代表任意次,所以.*组合代表匹配任意文本
.+        # .代表任一个字符,+代表至少一次,所以.+的组合表示匹配任意文本,但文本必须有内容(至少一个字符)

# ? 跟在 * 或者 + 后边用时,表示懒惰模式。也称非贪婪模式,使整个匹配成功的前提下使用最少的重复。
# 主要有如下这些,在满足原来含义的基础上采用最少重复
.*? 
.+?
*?
+?
??
{m,n}?
{n,}?

# 下面是一些常用的分组语法
(exp)          # 匹配exp,并捕获文本到自动命名的组里
(?<name>exp)   # 匹配exp,并捕获文本到名称为name的组里
(?:exp)        # 匹配exp,不捕获匹配的文本,也不给此分组分配组号
(?=exp)        # 匹配exp前面的位置
(?<=exp)       # 匹配exp后面的位置

   限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有 *+?{n}{n,}{n,m} 共6种。

 

2. re模块

   1)re.match:尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none,匹配成功re.match方法返回一个匹配的对象。

      可以使用 group() 提出分组截获的字符串:

      a. group() 同group(0)就是匹配正则表达式整体结果。

      b. group(1) 列出第一个括号匹配部分,group(2) 列出第二个括号匹配部分,group(3) 列出第三个括号匹配部分。

print(re.match("www", "www.baidu.com"))   # <re.Match object; span=(0, 3), match='www'>
print(re.match("com", "www.baidu.com"))   # None

result = re.match(r'(\d{3})-(\d{3,8})', '010-12345')
if result:
    print(result.group())   # 010-12345
    print(result.group(1))  # 010
    print(result.group(2))  # 12345

   2)re.search:搜索字符串中第一次出现正则表达式的模式 成功返回匹配对象 否则返回 None。

result = re.search(r'\d+', 'abc123def456ghi789')
if result:
    print(result.group())   # 123

      注:re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None,而 re.search 匹配整个字符串,直到找到一个匹配。

   3)re.split:用正则表达式指定的模式分隔符拆分字符串 返回列表。

result = re.split(r'\d+', 'abc123def456ghi789')
print(result)    # ['abc', 'def', 'ghi', '']

result = re.split(r'\s+', 'a b  c   d')
print(result)    # ['a', 'b', 'c', 'd']

line = 'asdf fjdk; afed, fjek,asdf, foo'
print(re.split(r'[;,\s]\s*', line))   # ['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']

      函数 re.split() 是非常实用的,因为它允许你为分隔符指定多个正则模式。比如,在上面的最后一个例子中,分隔符可以是逗号,分号或者是空格,并且后

      面紧跟着任意个的空格。只要这个模式被找到,那么匹配的分隔符两边的实体都会被当成是结果中的元素返回。返回结果为一个字段列表,这个跟 str.split() 返

      回值类型是一样的。

      当你使用 re.split() 函数时候,需要特别注意的是正则表达式中是否包含一个括号捕获分组。如果使用了捕获分组,那么被匹配的文本也将出现在结果列表中。

      比如,观察一下这段代码运行后的结果:

line = 'asdf fjdk; afed, fjek,asdf, foo'
fields = re.split(r'(;|,|\s)\s*', line)
print(fields)   # ['asdf', ' ', 'fjdk', ';', 'afed', ',', 'fjek', ',', 'asdf', ',', 'foo']

      如果你不想保留分割字符串到结果列表中去,但仍然需要使用到括号来分组正则表达式的话,确保你的分组是非捕获分组,形如 (?:...) 。比如:

line = 'asdf fjdk; afed, fjek,asdf, foo'
fields = re.split(r'(?:,|;|\s)\s*', line)
print(fields)   # ['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']

   4)re.sub:用指定的字符串替换原字符串中与正则表达式匹配的模式 可以用count指定替换的次数。

result = re.sub(r"\d+", "H", "asd23asd34455asd55")
print(result)          # asdHasdHasdH

result, count = re.subn(r"\d+", "H", "asd23asd34455asd55")
print(result, count)   # asdHasdHasdH 3

text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
s = re.sub(r'(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text)
print(s)   # Today is 2012-11-27. PyCon starts 2013-3-13.

      反斜杠数字比如 \3 指向前面模式的捕获组号。如果你打算用相同的模式做多次替换,考虑先编译它来提升性能。

   5)re.compile:编译正则表达式返回正则表达式对象。当我们在Python中使用正则表达式时, re模块内部会干两件事情

      a. 编译正则表达式,如果正则表达式的字符串本身不合法,会报错。

      b. 用编译后的正则表达式去匹配字符串。

result = re.compile(r'^(\d{3})-(\d{3,8})$')
print(result.match('010-12345').group(1))

   6)re.findall:match() 总是从字符串开始去匹配,如果你想查找字符串任意部分的模式出现位置,使用 findall() 方法去代替。

      findall() 方法会搜索文本并以列表形式返回所有的匹配。如果你想以迭代方式返回匹配,可以使用 finditer() 方法来代替。

      a. 当正则表达式中  没有括号时,就是正常匹配,以列表形式返回所有匹配。

string = "2345  3456  4567  5678"
regex = re.compile("\w+\s+\w+")
print(regex.findall(string))   # 有两个满足匹配条件,输出 ['2345  3456', '4567  5678']

      b. 当正则表达式中有  一个括号时,如"(\w+)\s+\w+"其输出的内容就是括号匹配到的内容。

string = "2345  3456  4567  5678"
regex = re.compile("(\w+)\s+\w+")
print(regex.findall(string))   # 有两个满足匹配条件,输出 ['2345', '4567']

      c. 当正则表达式中有两个括号时,如 "((\w+)\s+\w+)",其输出结果是一个list 中包含2个 tuple,每个tuple是一个括号匹配的内容。

string = "2345  3456  4567  5678"
regex = re.compile("((\w+)\s+\w+)")
print(regex.findall(string))   # [('2345  3456', '2345'), ('4567  5678', '4567')]

  

 
posted @ 2020-07-03 09:43  _yanghh  阅读(241)  评论(0编辑  收藏  举报