Python正则表达式教程:re模块详解

正则表达式(Regular Expression,通常简写为regex或regexp)是一种强大的文本处理工具,它使用一种特定的模式来描述和匹配字符串。正则表达式可以用于搜索、替换和验证文本中的特定字符序列

简单来说,可以理解为正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配

一、基本概念和常见元素

1、基本元素

  • 字符类:匹配方括号中的任意字符。例如,[abc] 匹配 “a”、“b” 或 “c”。
  • 范围:使用连字符 - 来表示字符范围。例如,[a-z] 匹配任何小写字母。
  • 否定字符类:在字符类前加上 ^ 符号可以匹配不在该字符类中的任意字符。例如,[^a-z] 匹配任何非小写字母的字符。
  • 元字符:具有特殊含义的字符,如 .(匹配任意字符,除了换行符)、*(匹配前面的元素零次或多次)、+(匹配前面的元素一次或多次)、?(匹配前面的元素零次或一次)等。
  • 锚点:用于指定匹配的位置,如 ^(匹配字符串的开头)和 $(匹配字符串的结尾)。
  • 2、分组和引用

  • 圆括号:用于分组,并捕获匹配的子字符串
  • 反向引用:使用 \1、\2 等来引用之前捕获的分组。
  • 3、修饰符和标志

  • 多行模式:使 ^ 和 $ 分别匹配每一行的开头和结尾,而不是整个字符串的开头和结尾。
  • 忽略大小写:使匹配时不区分大小写。
  • 全局搜索:搜索整个字符串中的所有匹配项,而不是只找到第一个就停止。
  • 4、常见应用

  • 验证:检查字符串是否符合特定的格式或规则,如电子邮件地址、电话号码等。
  • 搜索和替换:在文本中查找特定的模式,并用其他文本替换它。
  • 分割字符串:使用正则表达式作为分隔符来分割字符串。
  • 示例:

    import re
    
    text = "There are 123 apples and 456 oranges."
    pattern = r'\d+'  # 匹配一个或多个数字
    
    matches = re.findall(pattern, text)
    print(matches)  # 输出: ['123', '456']
    

    示例中, r'\d+' 是一个正则表达式,其中 \d 匹配任意数字, + 匹配前面的元素(即数字)一次或多次。re.findall() 函数用于在文本中查找所有匹配该正则表达式的子字符串。

    二、python 正则表达式 re模块

    re 模块使 Python 语言拥有全部的正则表达式功能。这个模块提供了一系列函数和方法,用于匹配和操作字符串。接下来将学习re模块的处理函数。

    1、re模块的基本函数

    >>> import re
    >>> dir(re)
    ['A', 'ASCII', 'DEBUG', 'DOTALL', 'I', 'IGNORECASE', 'L', 'LOCALE', 'M', 'MULTILINE', 
    'Match', 'NOFLAG', 'Pattern', 'RegexFlag', 'S', 'Scanner', 'T', 'TEMPLATE', 'U', 
    'UNICODE', 'VERBOSE', 'X', '_MAXCACHE', '_MAXCACHE2', '__all__', '__builtins__',
     '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', 
     '__path__', '__spec__', '__version__', '_cache', '_cache2', '_casefix',
      '_compile', '_compile_template', '_compiler', '_constants', '_parser',
       '_pickle', '_special_chars_map', '_sre', 'compile', 'copyreg', 'enum',
        'error', 'escape', 'findall', 'finditer', 'fullmatch', 'functools', 
        'match', 'purge', 'search', 'split', 'sub', 'subn', 'template']
    >>>
    

    和其他模块一样,在使用re模块来处理正则表达式时,要先导入 re 模块

    import re
    

    2、re模块函数使用

    正则表达式的语法和功能非常强大和灵活,可以通过学习更多的元字符、量词、边界匹配来扩展正则表达式的知识。
    (1)re.match()
    从字符串的起始位置匹配一个模式,如果匹配成功,返回一个匹配对象;否则返回None

    语法:

    re.match(pattern, string, flags=0)
    

    参数说明–
    pattern:匹配的正则表达式
    string :要匹配的字符串。
    flags :标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见:正则表达式修饰符 – 可选标志

    匹配对象方法:可使用 group(num)groups() 匹配对象函数来获取匹配表达式。

  • group(num=0) 匹配的整个表达式的字符串,group()可一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
  • groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
  • 示例如下:

    import re
    
    line = "Cats are smarter than dogs"
    
    matchObj = re.match(r'(.*) are (.*?) than (.*)', line)
    if matchObj:
        print("matchObj.group() : ", matchObj.group())  #输出 Cats are smarter than dogs
        print("matchObj.groups() : ", matchObj.groups()) #输出 ('Cats', 'smarter', 'dogs')
        print("matchObj.group(1) : ", matchObj.group(1)) #输出 Cats
        print("matchObj.group(2) : ", matchObj.group(2)) #输出 smarter
        print("matchObj.group(3) : ", matchObj.group(3)) #输出dogs
    
    else:
        print("No match!!")
    

    以上示例,正则表达式:r'(.*) are (.*?) than (.*)'
    其中 (.*):匹配任意数量的任意字符(除了换行符),并将它们捕获到第一个组中。
    (.*?):匹配任意数量的任意字符(除了换行符),但尽可能少地匹配(非贪婪模式),并将它们捕获到第二个组中。

    (2)re.search()
    扫描整个字符串,返回第一个成功匹配的对象。
    语法:

    re.search(pattern, string, flags=0)
    
  • re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None。
  • re.search匹配整个字符串,直到找到一个匹配。
  • import re
    print(re.match('hello', 'hello.python.com').span())  # 在起始位置匹配   输出:(0, 5)
    print(re.match('com', 'hello.python.com'))         # 不在起始位置匹配   输出:None
    
    print(re.search('hello', 'hello.python.com').span())  # 在起始位置匹配   输出:(0, 5)
    print(re.search('com', 'hello.python.com').span())    # 不在起始位置匹配  输出:(13, 16)
    

    (3)re.findall()
    在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果有多个匹配模式,则返回元组列表,如果没有找到匹配的,则返回空列表。

    注意: match 和 search 是匹配一次 findall 匹配所有。
    语法:

    findall(string, pos, endpos])
    

    参数说明:
    string : 待匹配的字符串。
    pos : 可选参数,指定字符串的起始位置,默认为 0。
    endpos : 可选参数,指定字符串的结束位置,默认为字符串的长度。

    示例:

    import  re
    pattern = re.compile(r'\d+') # 匹配一个或多个数字
    text= "I have 100 leomon trees and 20 rivers"
    findall= pattern.findall(text)
    findall1= pattern.findall(text,0,10)
    print("findall:",findall)  #输出:findall: ['100', '20']
    print("findall1:",findall1) #输出:findall1: ['100']
    

    (4)re.finditer()
    找到字符串中所有匹配的部分,并返回一个迭代器,产生匹配对象。
    语法:

    re.finditer(pattern, string, flags=0)
    

    示例:

    import  re
    pattern = re.compile(r'\d+') # 匹配一个或多个数字
    text= "I have 100 leomon trees and 20 rivers"
    findall= pattern.finditer(text)
    findall1= pattern.finditer(text,0,10)
    for match in findall:
        print (match.group() )
    for match in findall1:
        print (match.group() )
    

    运行结果:

    100
    20
    100
    

    (5)re.sub():检索和替换
    在字符串中查找匹配正则表达式的部分,并用另一个字符串替换它们。
    语法:

    re.sub(pattern, repl, string, count=0, flags=0)
    

    参数说明:
    pattern : 正则中的模式字符串。
    repl : 替换的字符串,也可为一个函数。
    string : 要被查找替换的原始字符串。
    count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。

    (6)re.split():分割
    split 方法按照能够匹配的子串将字符串分割后返回列表.
    语法:

    re.split(pattern, string, maxsplit=0, flags=0])
    

    参数说明:

  • pattern, string同上。
  • maxsplit 分隔次数,maxsplit=1 分隔一次,默认为
    0,不限制次数。
  • flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见:正则表达式修饰符 – 可选标志
  • (7)re.compile():
    编译正则表达式,根据一个模式字符串和可选的标志参数生成一个正则表达式( Pattern )对象。
    即:预编译一个正则表达式对象,然后重复使用它。
    该对象拥有一系列方法用于正则表达式匹配、搜索、替换等操作。

    语法:

    re.compile(pattern, flags=0)
    

    ① pattern : 一个字符串形式的正则表达式

    ② flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:

  • re.I 忽略大小写
  • re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
  • re.M 多行模式
  • re.S即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
  • re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
  • re.X 为了增加可读性,忽略空格和 # 后面的注释
  • 编译后的Pattern对象可以使用的方法包括match()、search()、findall()、finditer()、sub()、split()等
    示例:

    import re
    
    # 编译一个正则表达式
    pattern = re.compile(r'\d+')  # 匹配一个或多个数字
    
    # 使用编译后的正则表达式对象进行匹配
    text = "123 apples and 456 oranges."
    
    # 使用match方法从字符串的起始位置匹配
    match = pattern.match(text)
    if match:
        print("Match at start:", match.group()) #输出 Match at start: 123
    else:
        print("No match at start.")
    
    # 使用search方法在整个字符串中搜索匹配项
    search = pattern.search(text)
    if search:
        print("Match found:", search.group()) # 输出: Match found: 123
    else:
        print("No match found.")
    
    # 使用findall方法找到所有匹配项
    matches = pattern.findall(text)
    print("All matches:", matches)  # 输出: All matches: ['123', '456']
    

    compile()函数的好处:可将正则表达式的编译和匹配操作分开,多次重用编译后的正则表达式对象,提高性能。使代码更清晰、更易于维护。

    (8)修饰符和标志
    在编译正则表达式时,可以使用一些标志来改变匹配的行为。例如,re.IGNORECASE或re.I用于忽略大小写匹配。

    示例如下:

    import re
    
    print("----re.match()匹配----")
    pattern = r'\d+'  #匹配一个或多个数字
    text = "123 apples and 456 oranges"
    match = re.match(pattern, text)
    if match:
        print("Found:", match.group())  # 输出: Found: 123
    
    
    print("----re.search()扫描----")
    match = re.search(pattern, text)
    if match:
        print("Found:", match.group())  # 输出: Found: 123
    
    
    print("----re.findall()函数----")#找到字符串中所有匹配的部分,并返回一个列表
    matches = re.findall(pattern, text)
    print(matches)  # 输出: ['123', '456']
    
    
    print("----re.finditer()函数----")
    #找到字符串中所有匹配的部分,并返回一个迭代器,产生匹配对象。
    matches = re.finditer(pattern, text)
    for match in matches:
        print(match.group())  # 分别输出: 123 和 456
    
    
    print("----re.sub()替换----")
    new_text = re.sub(r'\d+', 'XXX', text)
    print(new_text)  # 输出: XXX apples and XXX oranges
    
    
    print("----re.split()分割----")
    words = re.split(r'\d+', text)
    print(words)  # 输出: ['', ' apples and ', ' oranges']
    
    
    print("----re.compile()预编译----")
    compiled_pattern = re.compile(r'\d+')
    matches = compiled_pattern.findall(text)
    print(matches)  # 输出: ['123', '456']
    
    
    print("----re.IGNORECASE或re.I用于忽略大小写匹配----") #修饰符和标志
    pattern = re.compile(r'apple', re.IGNORECASE)
    match = pattern.search('There is an Apple on the table.')
    if match:
        print("Found:", match.group())  # 输出: Found: Apple
    

    三、应用

    ‘(?P…)’ 分组匹配
    示例1:日期"The date is 2024-04-18."

    import re
    
    # 定义一个包含日期的字符串
    date_string = "The date is 2023-03-15."
    # 使用命名分组来匹配日期
    pattern = r"The date is (?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})."
    # 执行匹配
    match = re.search(pattern, date_string)
    # 如果匹配成功,打印命名分组的值
    if match:
        print("match.group:", match.group())
        print("group-Year:", match.group("year"))
        print("group-Month:", match.group("month"))
        print("group-Day:", match.group("day"))
    
        print("match.groups:", match.groups())
        print("groups-Year:", match.groups("year"))
        print("groups-Month:", match.groups("month"))
        print("groups-Day:", match.groups("day"))
    
        print("match.groupdict:", match.groupdict())
    
    else:
        print("No match found.")
    

    运行结果:

    match.group: The date is 2023-03-15.
    group-Year: 2023
    group-Month: 03
    group-Day: 15
    match.groups: ('2023', '03', '15')
    groups-Year: ('2023', '03', '15')
    groups-Month: ('2023', '03', '15')
    groups-Day: ('2023', '03', '15')
    match.groupdict: {'year': '2023', 'month': '03', 'day': '15'}
    

    示例2:识别身份证ID
    在Python的re模块中,当使用命名分组(即(?P…)语法)进行正则表达式匹配时,匹配对象会提供一个名为groupdict()的方法。这个方法返回一个字典,其中的键是命名分组的名称,值是相应分组匹配到的字符串。这对于提取和访问匹配到的命名分组非常有用。

    import re
    
    id = '4102211990xxxxxxxx'
    res = re.search(r'(?P<province>\d{3})(?P<city>\d{3})(?P<born_year>\d{4})', id[:10])
    if res:
        print(res.groupdict())#输出{'province': '410', 'city': '221', 'born_year': '1990'}
    else:
        print("No match found.")
    

    or

    import re
    id = '4102211990xxxxxxxx'
    res = re.search(r'(?P<province>\d{3})(?P<city>\d{3})(?P<born_year>\d{4})',id)
    print(res.groupdict())
    

    作者:大山很山

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python正则表达式教程:re模块详解

    发表回复