python 基础知正则表达式

# 正则表达式

### 应用场景

- 特定规律字符串的查找,切割、替换等
- 特定格式(邮箱、手机号、IP、URL等)的校验
- 爬虫项目中,提取特定内容

### 使用原则

- 只要使用字符串函数能够解决的问题就不要使用正则
- 正则的效率比较低,同时会降低代码的可读性
- 世界上最难理解的三样东西:医生的处方、道士的神符、码农的正则
- 提醒:正则是用来写的,不是用来读的;在不清楚功能的情况下,不要阅读别人的正则

### 基本使用

- 说明:正则的解析不是我们来做的,需要借助`re`模块

- 相关函数:

  - match:只从开头进行匹配,匹配到就返回结果对象,没有找到返回None
  - search:从任意位置匹配,功能同上,都是单次匹配(找到就停)

  ```python
  m = re.search('abc', 'hadajabcadjlae')

  if m:
      # 返回匹配的内容
      print(m.group())
      # 返回匹配内容的位置
      print(m.span())
  ```

  - findall:全部匹配,返回所有匹配的到结果列表,没有找到返回空列表

  ```python
  f = re.findall('abcd', 'abcasjdlaabcaksjd;abcasdjla')
  print(f)
  ```

  - compile:创建正则表达式对象,可以让创建正则对象和内容匹配分开操作

  ```python
  # 可以先生成正则表达式对象,然后再进行匹配
  c = re.compile('cba')
  # print(type(c))

  # 从开头匹配
  # m = c.match('cbasdhaj;acbaalsdk')
  # 从任意位置匹配
  m = c.search('casdhaj;acbaalsdk')

  if m:
      print(m.group())

  # 匹配所有
  f = c.findall('ahkjdcbasdkjalcbasakldjacba')
  print(f)
  ```

  > 此方式可以分开操作,比较灵活

### 正则语法

- 单个字符

  ```
  普通字符:简单理解就是一对一的完全匹配
  []:中间的任意一个字符
      [abc]:abc的任意一个字符
      [0-9]:任意的数字字符
      [a-zA-Z]:任意的字母
      [^0-9]:非数字字符
  . :除'\n'以外的任意字符
  \d:数字字符,等价于[0-9]
  \D:非数字字符,等价于[^0-9]
  \w:匹配字(数字、字母、下划线)
  \W:匹配非字(\w相反的内容)
  \s:空白字符(\n、\r、\t、空格)
  \S:非空白字符(\s相反的内容)
  \b:词边界(开头、结尾、空格、标点)
  \B:非词边界(\b相反的内容)
  ```

- 次数限定:修饰前面的单个字符出现的次数

  ```
  *:任意次
  +:至少一次
  ?:至多一次
  {m}:指定m次
  {m,n}:m <= 次数 <=n
  {m,}:至少m次
  {,m}:至多m次
  ```

- 边界限定

  - ^:以指定的内容开头
  - $:以指定的内容结尾
  - 示例:

  ```python
  import re

  # 只从开头匹配
  # f = re.findall('^hello', 'asjdhelloaskd')
  # 只从结尾匹配
  f = re.findall('world$', 'asjdhelloaskworld')
  # 同时限制开头和结尾
  f = re.findall('^\w*$', 'asjdhelloaskworld')
  print(f)
  ```

- 优先级与整体

  ```python
  import re

  # |:表示或,拥有最低的优先级
  # ():可以表示一个整体
  s = re.search('hell(o|w)orld', 'akdhahellworld')

  if s:
      print(s.group())
  ```

- 分组匹配

  - 示例1:

  ```python
  import re

  c = re.compile('(\d+)([a-z]+)(\d+)')

  s = c.search('agaj2635sdhasda237adjsd')

  if s:
      # 0:表示完整匹配内容,之后的数字表示第几组,也就是第几个()匹配的内容
      print(s.group(0), s.span(0))
      print(s.group(1), s.span(1))
      print(s.group(2), s.span(2))
      print(s.group(3), s.span(3))
  ```

  - 示例2:

  ```python
  import re

  # 固定匹配
  # c = re.compile('<div><a>\w+</a></div>')
  # 动态匹配:匹配两次嵌套的标签
  # c = re.compile('<[a-z]+><[a-z]+>\w+</[a-z]+></[a-z]+>')
  # 无名分组:\1、\2分别表示前面的第一组、第二组匹配的内容
  # c = re.compile(r'<([a-z]+)><([a-z]+)>\w+</\2></\1>')
  # 命名分组:给分组()起名字
  c = re.compile(r'<(?P<one>[a-z]+)><(?P<two>[a-z]+)>\w+</(?P=two)></(?P=one)>')

  s = c.search('<div><a>百度一下</a></div>')

  if s:
      print(s.group())
      # 返回所有组的信息,是一个元组
      print(s.groups())
      # 返回分组的字典,键是组的名字,值时匹配的内容
      print(s.groupdict())
  ```

- findall

  ```python
  import re

  # 按照正则进行匹配,但是添加()后,结果只显示()匹配的内容
  f = re.findall('A(abc)A', 'asdjAabcAasdjAabcAsdkabca')

  print(f)
  ```

- 贪婪匹配

  - 贪婪:最大限度的匹配。正则的匹配默认是贪婪的
  - 非贪婪:只要满足条件,能少匹配就少匹配。可以使用'?'取消贪婪
  - 示例:

  ```python
  import re

  # .+?:取消至少一次的贪婪匹配
  # c = re.compile('a.+?b')

  # .*?:取消任意多次的贪婪匹配
  c = re.compile('a.*?b')

  s = c.search('sdhaasdajasksdbsdjbsdk')

  if s:
      print(s.group())
  ```

- 匹配模式

  - 说明:匹配模式就是对默认的匹配原则进行整体的修饰
  - 示例:

  ```python
  import re

  # re.I:表示忽略大小写
  # s = re.search(r'hello', 'Hello', re.I)

  # re.M:多行处理,默认会把字符当做一行处理
  s = re.search(r'^hello', 'asdkasj\nhelloajsdhkas', re.M)

  # string = '<div>hello</div>'
  string = '''<div>
  hello
  </div>'''
  # re.S:是.可以匹配任意,作为单行处理(忽略\n)
  s = re.search(r'<div>.*?</div>', string, re.S)

  if s:
      print(s.group())
  ```

- 字符转义

  - 匹配凡是跟正则语法相关的字符都需要需要进转义
  - 示例:

  ```python
  import re

  # python    \\\d    \\\\d   r'\\d'
  # re        \\d     \\d     \\d
  # 实际        \d      \d      \d

  # 推荐使用,否则需要写很多\
  c = re.compile(r'\\d')

  s = c.search('\d')

  if s:
      print(s.group())
   
  # 匹配'\b'字符串
  c = re.compile(r'\b')

  # \b本身有特殊含义
  s = c.search(r'\b')
  if s:
      print('成功', s.group())       
  ```
  > 在定义字符串的开头添加'r'表示原始字符串,可以轻松解决很多关于转义的问题

- 正则切割

  ```python
  import re

  c = re.compile(r'\d')

  string = '正则其实不难1但是学完之后2发现什么也不出来3是这样吧'

  # 字符串是固定切割,不能解决某类的匹配切割问题
  # print(string.split('1'))
  # 按照正则进行切割
  ret = c.split(string)
  print(ret)

  # 整体方案
  print(re.split(r'\d', string))
  ```




- 正则替换

  ```python
  string = 'helloadjasdhelloskdjalkhellosdjka'
  # 字符串替换
  new_string = string.replace('hello', 'world', 2)
  print(new_string)

  import re

  s = 'how1are2you'
  # 正则替换
  # s2 = re.sub(r'\d', ' ', s)
  # 替换时可以传递一个函数,使用函数的返回值进行替换
  def double(s):
      return str(int(s.group()) * 2)
      # return 'xxx'
  # 使用专门的处理函数,可以认为的干预替换过程
  s2 = re.sub(r'\d', double, s)
  print(s2)
  

 

posted @ 2018-12-22 17:59  青春叛逆者  阅读(215)  评论(0编辑  收藏  举报