正则表达式

核心步骤

  • 先使用 re.compile() 编译正则表达式字符串,然后使用 match() , findall() 或者 finditer() 等方法

compile 函数

  • 用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match()search() 这两个函数使用
  • re.compile(pattern[, flags])
  • 如果想使用同一个模式去做多次匹配,你应该先将模式字符串预编译为模式对象

匹配函数方法

re.match()

  • re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none
  • re.match(pattern, string, flags=0)

pattern:匹配的正则表达式
string :要匹配的字符串
flags :标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

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

re.search()

  • 扫描整个字符串并返回第一个成功的匹配。

re.sub()

  • re.sub用于替换字符串中的匹配项。
  • re.sub(pattern, repl, string, count=0)
    • repl : 替换的字符串,也可为一个函数,当repl 参数是一个函数时,我们可以做许多变化
    • count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。

如果除了替换后的结果外,你还想知道有多少替换发生了,可以使用 re.subn()来代替。

  • newtext,n = datepat.subn(r'\3-\1-\2',text)

re.dindall()

  • 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表
  • findall(string[, pos[, endpos]])
    • pos 可选参数,指定字符串的起始位置,默认为 0。
    • endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。
    • 举例:
      pattern = re.compile(r'\d+')   # 查找数字
      result1 = pattern.findall('runoob 123 google 456')
      result2 = pattern.findall('run88oob123google456', 0, 10)
      
  • 注1:matchsearch 是匹配一次,而findall 匹配所有
  • 注2:findall() 方法会搜索文本并以列表形式返回所有的匹配。如果你想以迭代方式返回匹配,可以使用 finditer() 方法来代替

re.finditer()

  • 和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。
  • re.finditer(pattern, string, flags=0)

re.split()

  • split 方法按照能够匹配的子串将字符串分割后返回列表
  • re.split(pattern, string[, maxsplit=0, flags=0])
    • maxsplit:分隔次数
    • maxsplit=1 分隔一次,默认为 0,不限制次数。
  • 举例:
    >>> re.split('\W+', 'runoob, runoob, runoob.')
    ['runoob', 'runoob', 'runoob', '']
    

正则表达式模式

详情可见表

注意要点:

  • 字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。

  • 只有被转义时才表示特殊的含义

  • 标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。

  • 反斜杠本身需要使用反斜杠转义。

  • 由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\t',等价于 \\t)匹配相应的特殊字符。

  • r 即后面的字符串为原始字符串,防止计算机将 \ 理解为转义字符,

  • 注:

  • 当写正则式字符串的时候,相对普遍的做法是使用原始字符串比如 r'(\d+)/(\d+)/(\d+)' 。这种字符串将不去解析反斜杠,这在正则表达式中是很有用的。如果不这样做的话,你必须使用两个反斜杠,类似 '(\\d+)/(\\d+)/(\\d+)'

  • * 操作符是贪婪的,因此匹配操作会查找最长的可能匹配,
    为了修正这个问题,可以在模式中的 *操作符后面加上?修饰符,这样就使得匹配变成非贪婪模式,从而得到最短的匹配

  • 在一个模式字符串中,点 (.) 匹配除了换行外的任何字符。然而,如果你将点(.) 号放在开始与结束符 (比如引号) 之间的时候,那么匹配操作会查找符合模式的最长可能匹配。这样通常会导致很多中间的被开始与结束符包含的文本被忽略掉,并最终被包含在匹配结果字符串中返回。通过在 *或者 + 这样的操作符后面添加一个? 可以强制匹配算法改成寻找最短的可能匹配。

  • 在定义正则式的时候,通常会利用括号去捕获分组,捕获分组可以使得后面的处理更加简单,因为可以分别将每个组的内容提取出来

正则表达式修饰符 - 可选标志

  • re.I 忽略大小写,使匹配对大小写不敏感
  • re.L 表示特殊字符集\w, \W, \b, \B, \s, \S依赖于当前环境,做本地化识别(locale-aware)匹配
  • re.M 多行模式,re.M,将所有行的尾字母输出 multiple,多行匹配,影响 ^ 和 $
  • re.S 即为' . '并且包括换行符在内的任意字符(' . '不包括换行符)
  • re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S依赖于 Unicode 字符属性数据库,这个标志影响 \w, \W, \b, \B.
  • re.X 为了增加可读性,忽略空格和' # '后面的注释,该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

现存疑问点:

  • 疑问1:
    >>>line = 'asdf fjdk; afed, fjek,asdf, foo'
    >>>import re
    >>>re.split(r'[;,\s]\s*',line)
    ['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']
    

问题:这里re.split(r'[;,\s]\s*',line)如果不加\s*,结果则是['asdf', 'fjdk', '', 'afed', '', 'fjek', 'asdf', '', 'foo']
所以,加了\s*的意义造成这样好处的原理是什么呢?

  • 疑问2:
>>>from fnmatch import fnmatch,fnmatchcase
>>>names = ['Dat1.csv', 'Dat2.csv', 'config.ini', 'foo.py']
>>>[name for name in names if fnmatch(name, 'Dat*.csv')]
['Dat1.csv', 'Dat2.csv']

问题:这里的fnmatch(name, 'Dat*.csv')]中的'Dat*.csv'为何是用*才可以实现这样的匹配呢,用+号却不行

  • 疑问3:
>>>datepat = re.compile(r'(\d+)/(\d+)/(\d+)$')
>>>m1 = datepat.match('11/27/2012abcdef')
>>>m2 = datepat.match('11/27/2012')
>>>m2.group()
'11/27/2012'

问题:为何m1.group()就会报错呢?而m2.group()却正常?

  • 疑问4:
`re.compile(r'/\*((?:.|\n)*?)\*/')`理解不来啊
  • 疑问5:
>>>s = ' hello             world \n'
>>>import re
>>>re.sub('\s+',' ',s)
' hello world '

问题:这里的匹配串用\s+\s*,甚至是\s?都是不同的,如何理解?

你可能感兴趣的:(正则表达式)