正则表达式

AffettoIris 2023-3-6 2,613 3/6

re库

re.match(pattern, string)

推荐正则表达式字符串用r前缀,r表示raw,不做任何修改,原生。

从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none

正则表达式

findall(pattern, string, flags=0)

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表

print(re.findall(r'ab*', 'acabc'))
# ['a', 'ab']

第三个参数 flags有忽略大小写的re.I, 让模式更易读的re.X等,re.S做的事情是: 原本.是不匹配换行符的,它让.也匹配换行符。re.M做的事情是: 原本^只匹配字符串的头,$只匹配字符串的尾,它让^匹配每行的开头,让$匹配每行的结尾。

text = """First line.
Second line.
Third line."""

pattern = "^(.*?)$"
print(re.findall(pattern, text, flags=0))  # []
print(re.findall(pattern, text, re.S))  # ['First line.\nSecond line.\nThird line.']
print(re.findall(pattern, text, re.M))  # ['First line.', 'Second line.', 'Third line.']

re.search()

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

print(re.search(r'ab*', 'acabc') # <re.Match object; span=(0, 1), match='a'>
# span=(0, 1)表示结果a取自字符串的从0取不到1位
print(re.search(r'ab*', 'acabc').group()) # a

正则表达式group()

正则表达式中,group()用来按分组提取字符串

import re
a = "123abc456"
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a)) 
# <re.Match object; span=(0, 9), match='123abc456'>
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0))   #123abc456,返回整体
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1)) #123
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2)) #abc
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3))  #456

# 正则表达式中的三组括号把匹配结果分成三组([0-9]*)和([a-z]*)和([0-9]*),
print(re.search(r'ab*', 'acabc').group()) 等价于
print(re.search(r'(ab*)', 'acabc').group(0)) # a 

pattern规则

  1. 字符串"\d"匹配0~9之间的一个数值

  2. "+"前面一个字符匹配字符一次或者多次.

  3. "*"前面一个字符匹配字符零次或者多次.

  4. "?"前面一个字符匹配字符零次或者一次.

  5. ".“代表除”\n"外的任何一个字符

  6. ()用于把单个匹配结果细分成多组,便于.group()方法,经常与+、*、?联用,使得只对()内进行重复.

    尽管re.findall()无group()语法,但依然可以分组

    print(re.findall(r'(<div>)(.*?)(</div>)', '<div>123qwe</div>')) 
    # [('<div>', '123qwe', '</div>')]
    print(re.findall(r'(<div>)(.*?)(</div>)', '<div>123qwe</div>')[0][0]) # <div>
    print(re.findall(r'<div>.*?</div>', '<div>123qwe</div>')[0]) # <div>123qwe</div>
    
    print(re.findall(r'abc(.*?)(\d)def', 'abc12.1fe2def', re.S)) # [('12.1fe', '2')]
    print(re.findall(r'abc.*?\ddef', 'abc12.1fe2def', re.S)) # ['abc12.1fe2def']
  7. “|”表示左边或右边

    print(re.search(r"ab|ba", "abc").group()) # ab
    print(re.search(r"ab|ba", "bac").group()) # ba
  8. "\r""\n""\t""\\"分别表示回车、换行、制表符号与反斜线自己本身
  9. 字符"\b"表示单词到此结尾,包括各种空白字符或者整个字符串到头了.

    print(re.search(r"car\b", "the car is big.").group()) # car
    print(re.search(r"car\b", "the caris big.")) # None
  10. []表示任选择一个[]中的字符例如[0-9]表示0-9的其中一个数字,[A-Z]表示A-Z的其中一个大写字符,[0-9A-z]表示0-9的其中一个数字或者A-z的其中一个字母

  11. "^"出现在[]的第一个字符位置,就代表取反,例如[ ^ab0-9]表示任选一个不是a、b,也不是0-9的字符.

  12. "\s"匹配任何空白字符,等价"[\r\n\x20\t\f\v]" space

  13. "\w"匹配任何单词字符,不限数字、英文字母、下划线,等价于"[_a-zA-Z0-9]"。与\s相对。 word

  14. "\d"匹配任意数字 dec

  15. “\S”代表所有非“\s”;“\W”代表所有非“\w”;“\D”代表所有非“\d”

  16. "$"表示字符串的结尾位置

    print(re.search(r"big$", "big car is big")) # span=(11, 14),而非(0, 3)
  17. “^”不出现在[]里时代表字符串的开头,与“$”相对

  18. {m}匹配前一个字符m次;{m, n}匹配前一个字符m到n次

  19. 正则表达式之.*与.*?
    print(re.findall(r'(<div>)(.*)(</div>)', '<div>123qwe</div></div>')[0]) 
    # ('<div>', '123qwe</div>', '</div>')
    print(re.findall(r'(<div>)(.*?)(</div>)', '<div>123qwe</div></div>')[0])
    # ('<div>', '123qwe', '</div>')
    
    简单一句话:.* 具有贪婪的性质,首先匹配到不能匹配为止,根据后面的正则表达式,会进行回溯。.*?则相反,一个匹配以后,就往下进行,所以不会进行回溯,具有最小匹配的性质。
    非要深奥点,看下面:

    正则表达式

    源字符串:"**Regex"**

    正则表达式:"**.*"**

    注:为了能够看清晰匹配过程,上面的空隙留得较大,实际源字符串为“”Regex””,下同。

    来看一下匹配过程。首先由第一个“"”取得控制权,匹配位置0位的“"”,匹配成功,控制权交给“.*”。

    .*”取得控制权后,由于“*”是匹配优先量词,在可匹配可不匹配的情况下,优先尝试匹配。从位置1处的“R”开始尝试匹配,匹配成功,继续向右匹配,匹配位置2处的“e”,匹配成功,继续向右匹配,直到匹配到结尾的“”,匹配成功,由于此时已匹配到字符串的结尾,所以“.*”结束匹配,将控制权交给正则表达式最后的“"”。

    "”取得控制权后,由于已经在字符串结束位置,匹配失败,向前查找可供回溯的状态,控制权交给“.*”,由“.*”让出一个字符,也就是字符串结尾处的“”,再把控制权交给正则表达式最后的“"”,由“"”匹配字符串结尾处的“"”,匹配成功。

    此时整个正则表达式匹配成功,其中“.*”匹配的内容为“Regex”,匹配过程中进行了一次回溯。

    接下来看一下非贪婪模式简单的匹配过程。

    源字符串:"**Regex"**

    正则表达式:"**.*?"**

    看一下非贪婪模式的匹配过程。首先由第一个“"”取得控制权,匹配位置0位的“"”,匹配成功,控制权交给“.*?”。

    .*?”取得控制权后,由于“*?”是忽略优先量词,在可匹配可不匹配的情况下,优先尝试不匹配**,由于“*”等价于“{0,}”,所以在忽略优先的情况下,可以不匹配任何内容。从位置1处尝试忽略匹配,也就是不匹配任何内容,将控制权交给正则表达式最后的“”**”。

    "”取得控制权后,从位置1处尝试匹配,由“"”匹配位置1处的“R”,匹配失败,向前查找可供回溯的状态,控制权交给“.*?”,由“.*?”吃进一个字符,匹配位置1处的“R”,再把控制权交给正则表达式最后的“"”。

    "”取得控制权后,从位置2处尝试匹配,由“"”匹配位置1处的“e”,匹配失败,向前查找可供回溯的状态,重复以上过程,直到由“.*?”匹配到“x”为止,再把控制权交给正则表达式最后的“"”。

    "”取得控制权后,从位置6处尝试匹配,由“"”匹配字符串最后的“"”,匹配成功。

    此时整个正则表达式匹配成功,其中“.*?”匹配的内容为“Regex”,匹配过程中进行了五次回溯。

- THE END -

AffettoIris

10月16日15:58

最后修改:2023年10月16日
0

非特殊说明,本博所有文章均为博主原创。

共有 0 条评论