zoukankan      html  css  js  c++  java
  • Python 正则表达式:re 模块【一篇就够了】

    Python 正则表达式:re 模块【一篇就够了】

    学习网址:https://blog.csdn.net/weixin_39020133/article/details/105493774?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase

    创建正则表达式对象
    phoneNumRegex = re.compile(r'ddd-ddd-dddd')
    
    • 1

    传入一个字符串值,表示正则表达式,它将返回一个 Regex 模式对象(或者就简称为Regex对象)。

    匹配 Regex 对象

    如果字符串中没有找到该正则表达式模式,search()方法将返回 None。如果找到了该模式,search()方法将返回一个 Match 对象。Match 对象有一个 group()方法,它返回被查找字符串中实际匹配的文本

    phoneNumRegex = re.compile(r'ddd-ddd-dddd')
    mo = phoneNumRegex.search('My number is 415-555-4242.')
    print('Phone number found: ' + mo.group())
    Phone number found: 415-555-4242
    
    • 1
    • 2
    • 3
    • 4
    利用括号分组

    正则表达式字符串中的第一对括号是第 1 组。第二对括号是第 2 组。向 group()匹配对象方法传入整数 1 或 2,就可以取得匹配文本的不同部分。向 group()方法传入 0 或不传入参数,将返回整个匹配的文本。

    >>> phoneNumRegex = re.compile(r'(ddd)-(ddd-dddd)')
    >>> mo = phoneNumRegex.search('My number is 415-555-4242.')
    >>> mo.group(1)
    '415' 
    
    • 1
    • 2
    • 3
    • 4

    如果想要一次就获取所有的分组,请使用 groups()方法,注意函数名的复数形式。

    >>> mo.groups()
    ('415', '555-4242')
    >>> areaCode, mainNumber = mo.groups()
    >>> print(areaCode)
    415
    >>> print(mainNumber)
    555-4242
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    管道匹配多个分组

    字符|称为“管道”。希望匹配许多表达式中的一个时,就可以使用它。如果Batman 和 Tina Fey 都出现在被查找的字符串中,第一次出现的匹配文本,将作为 Match 对象返回。

    >>> heroRegex = re.compile (r'Batman|Tina Fey')
    >>> mo1 = heroRegex.search('Batman and Tina Fey.')
    >>> mo1.group()
    'Batman'
    >>> mo2 = heroRegex.search('Tina Fey and Batman.')
    >>> mo2.group()
    'Tina Fey' 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    也可以使用管道来匹配多个模式中的一个,作为正则表达式的一部分。例如,假设你希望匹配 ‘Batman’ 、’Batmobile’ 、’Batcopter’ 和 ‘Batbat’中任意一个。因为所有这些字符串都以Bat 开始,所以如果能够只指定一次前缀,就很方便。这可以通过括号实现。在交互式环境中输入以下代码:

    >>> batRegex = re.compile(r'Bat(man|mobile|copter|bat)')
    >>> mo = batRegex.search('Batmobile lost a wheel')
    >>> mo.group()
    'Batmobile'
    >>> mo.group(1)
    'mobile
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    用问号实现可选匹配

    有时候,想匹配的模式是可选的。就是说,不论这段文本在不在,正则表达式都会认为匹配。字符?表明它前面的分组在这个模式中是可选的。例如,在交互式环境中输入以下代码:

    >>> batRegex = re.compile(r'Bat(wo)?man')
    >>> mo1 = batRegex.search('The Adventures of Batman')
    >>> mo1.group()
    'Batman'
    >>> mo2 = batRegex.search('The Adventures of Batwoman')
    >>> mo2.group()
    'Batwoman'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    你可以认为?是在说,“匹配这个问号之前的分组零次或一次”。

    用星号匹配零次或多次

    *(称为星号)意味着“匹配零次或多次”,即星号之前的分组,可以在文本中出现任意次。它可以完全不存在,或一次又一次地重复。让我们再来看看 Batman 的例子。

    >>> batRegex = re.compile(r'Bat(wo)*man')
    >>> mo1 = batRegex.search('The Adventures of Batman')
    >>> mo1.group()
    'Batman'
    >>> mo2 = batRegex.search('The Adventures of Batwoman')
    >>> mo2.group()
    'Batwoman'
    >>> mo3 = batRegex.search('The Adventures of Batwowowowoman')
    >>> mo3.group()
    'Batwowowowoman'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    对于’Batman’,正则表达式的(wo)*部分匹配 wo 的零个实例。对于’Batwoman’(wo)*匹配 wo 的一个实例。对于’Batwowowowoman’(wo)*匹配wo 的 4 个实例。

    用加号匹配一次或多次

    *意味着“匹配零次或多次”,+(加号)则意味着“匹配一次或多次”。星号不要求分组出现在匹配的字符串中,但加号不同,加号前面的分组必须“至少出现一次”。

    >>> batRegex = re.compile(r'Bat(wo)+man')
    >>> mo1 = batRegex.search('The Adventures of Batwoman')
    >>> mo1.group()
    'Batwoman'
    >>> mo2 = batRegex.search('The Adventures of Batwowowowoman')
    >>> mo2.group()
    'Batwowowowoman'
    >>> mo3 = batRegex.search('The Adventures of Batman')
    >>> mo3 == None
    True
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    用花括号匹配特定次数

    正则表达式(Ha){3}将匹配字符串’HaHaHa’,但不会匹配’HaHa’,因为后者只重复了(Ha)分组两次。 除了一个数字,还可以指定一个范围,即在花括号中写下一个最小值、一个逗号和一个最大值。例如,正则表达式Ha{3,5}将匹配’HaHaHa’’HaHaHaHa’’HaHaHaHaHa’。 也可以不写花括号中的第一个或第二个数字,不限定最小值或最大值。例如, Ha{3,}将匹配 3 次或更多次实例,Ha{,5}将匹配 0 到 5 次实例。

    >>> haRegex = re.compile(r'(Ha){3}')
    >>> mo1 = haRegex.search('HaHaHa')
    >>> mo1.group()
    'HaHaHa'
    >>> mo2 = haRegex.search('Ha')
    >>> mo2 == None
    True 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这里,Ha{3}匹配’HaHaHa’,但不匹配’Ha’。因为它不匹配’Ha’,所以 search返回 None

    贪心和非贪心匹配

    在字符串’HaHaHaHaHa’中,因为Ha{3,5}可以匹配 3 个、4 个或 5 个实例,你可能会想,为什么在前面花括号的例子中,Match对象的 group调用会返回’HaHaHaHaHa’,而不是更短的可能结果。毕竟,’HaHaHa’’HaHaHaHa’也能够有效地匹配正则表达式Ha{3,5}。 Python 的正则表达式默认是“贪心”的,这表示在有二义的情况下,它们会尽可能匹配最长的字符串。花括号的“非贪心”版本匹配尽可能最短的字符串,即在结束的花括号后跟着一个问号。 在交互式环境中输入以下代码,注意在查找相同字符串时,花括号的贪心形式和非贪心形式之间的区别:

    >>> greedyHaRegex = re.compile(r'(Ha){3,5}')
    >>> mo1 = greedyHaRegex.search('HaHaHaHaHa')
    >>> mo1.group()
    'HaHaHaHaHa'
    >>> nongreedyHaRegex = re.compile(r'(Ha){3,5}?')
    >>> mo2 = nongreedyHaRegex.search('HaHaHaHaHa')
    >>> mo2.group()
    'HaHaHa' 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    请注意,问号在正则表达式中可能有两种含义:声明非贪心匹配或表示可选的分组。这两种含义是完全无关的。

    findall方法

    findall()方法返回一个字符串列表,只要在正则表达式中没有分组。列表中的每个字符串都是一段被查找的文本,它匹配该正则表达式。在交互式环境中输入以下代码:

    >>> phoneNumRegex = re.compile(r'ddd-ddd-dddd') # has no groups
    >>> phoneNumRegex.findall('Cell: 415-555-9999 Work: 212-555-0000')
    ['415-555-9999', '212-555-0000']
    
    • 1
    • 2
    • 3

    如果在正则表达式中有分组,那么 findall将返回元组的列表。每个元组表示一个找到的匹配,其中的项就是正则表达式中每个分组的匹配字符串。为了看看findall()的效果,请在交互式环境中输入以下代码(请注意,被编译的正则表达式现在有括号分组):

    >>> phoneNumRegex = re.compile(r'(ddd)-(ddd)-(dddd)') # has groups
    >>> phoneNumRegex.findall('Cell: 415-555-9999 Work: 212-555-0000')
    [('415', '555', '1122'), ('212', '555', '0000')] 
    
    • 1
    • 2
    • 3

    作为findall()方法的返回结果的总结,请记住下面两点:

    1. 如果调用在一个没有分组的正则表达式上,例如ddd-ddd-dddd,方法findall将返回一个匹配字符串的列表,例如[‘415-555-9999’, ‘212-555-0000’]
    2. 如果调用在一个有分组的正则表达式上,例如ddd-ddd-dddd,方 法findall将返回一个字符串的元组的列表(每个分组对应一个字符串),例如[‘415′,‘555′,‘1122′, ‘212′,‘555′,‘0000′]
    字符分类
    字符涵义
    d 0 到 9 的任何数字
    D 除 0 到 9 的数字以外的任何字符
    w 任何字母、数字或下划线字符(可以认为是匹配“单词”字符)
    W 除字母、数字和下划线以外的任何字符
    s 空格、制表符或换行符(可以认为是匹配“空白”字符)
    S 除空格、制表符和换行符以外的任何字符
    >> xmasRegex = re.compile(r'd+sw+')
    >> xmasRegex.findall('12 drummers, 11 pipers, 10 lords, 9 ladies, 8 maids, 7
    swans, 6 geese, 5 rings, 4 birds, 3 hens, 2 doves, 1 partridge')
    ['12 drummers', '11 pipers', '10 lords', '9 ladies', '8 maids', '7 swans', '6
    geese', '5 rings', '4 birds', '3 hens', '2 doves', '1 partridge']
    
    • 1
    • 2
    • 3
    • 4
    • 5

    正则表达式d+sw+匹配的文本有一个或多个数字d+,接下来是一个空白字符s,接下来是一个或多个字母/数字/下划线字符w+findall()方法将返回所有匹配该正则表达式的字符串,放在一个列表中。

    建立自己的字符分类

    有时候你想匹配一组字符,但缩写的字符分类(d、w、s 等)太宽泛。你可以用方括号定义自己的字符分类。例如,字符分类[aeiouAEIOU]将匹配所有元音字符,不论大小写。在交互式环境中输入以下代码:

    >>> vowelRegex = re.compile(r'[aeiouAEIOU]')
    >>> vowelRegex.findall('RoboCop eats baby food. BABY FOOD.')
    ['o', 'o', 'o', 'e', 'a', 'a', 'o', 'o', 'A', 'O', 'O'] 
    
    • 1
    • 2
    • 3

    也可以使用短横表示字母或数字的范围。例如,字符分类[a-zA-Z0-9]将匹配所有小写字母、大写字母和数字。 请注意,在方括号内,普通的正则表达式符号不会被解释。这意味着,你不需要前面加上倒斜杠转义.、*、?或字符。例如,字符分类将匹配数字 0 到 5 和一个句点。你不需要将它写成[0-5.]。 通过在字符分类的左方括号后加上一个插入字符(^),就可以得到“非字符类”。非字符类将匹配不在这个字符类中的所有字符。例如,在交互式环境中输入以下代码:

    >>> consonantRegex = re.compile(r'[^aeiouAEIOU]')
    >>> consonantRegex.findall('RoboCop eats baby food. BABY FOOD.')
    ['R', 'b', 'c', 'p', ' ', 't', 's', ' ', 'b', 'b', 'y', ' ', 'f', 'd', '.', '
    ', 'B', 'B', 'Y', ' ', 'F', 'D', '.']
    
    • 1
    • 2
    • 3
    • 4

    现在,不是匹配所有元音字符,而是匹配所有非元音字符。

    插入字符和美元字符
    • ^),表明匹配必须发生在被查找文本开始处。
    • $),表示该字符串必须以这个正则表达式的模式结束。
      可以同时使用^$,表明整个字符串必须匹配该模式,也就是说,只匹配该字符串的某个子集是不够的。正则表达式r’^Hello’匹配以’Hello’开始的字符串。在交互式环境中输入以下代码:
    >>> beginsWithHello = re.compile(r'^Hello')
    >>> beginsWithHello.search('Hello world!')
    <_sre.SRE_Match object; span=(0, 5), match='Hello'>
    >>> beginsWithHello.search('He said hello.') == None
    True
    
    • 1
    • 2
    • 3
    • 4
    • 5

    正则表达式r’d$’匹配以数字 0 到 9 结束的字符串。在交互式环境中输入以下代码:

    >>> endsWithNumber = re.compile(r'd$')
    >>> endsWithNumber.search('Your number is 42')
    <_sre.SRE_Match object; span=(16, 17), match='2'>
    
    • 1
    • 2
    • 3

    正则表达式r’^d+$’匹配从开始到结束都是数字的字符串。在交互式环境中输入以下代码:

    >>> wholeStringIsNum = re.compile(r'^d+$')
    >>> wholeStringIsNum.search('1234567890')
    <_sre.SRE_Match object; span=(0, 10), match='1234567890'>
    >>> wholeStringIsNum.search('12345xyz67890') == None
    True
    >>> wholeStringIsNum.search('12 34567890') == None
    True
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    前面交互式脚本例子中的最后两次search()调用表明,如果使用了^$,那么整个字符串必须匹配该正则表达式。

    通配字符

    在正则表达式中,.(句点)字符称为“通配符”。它匹配除了换行之外的所有字符。例如,在交互式环境中输入以下代码:

    >>> atRegex = re.compile(r'.at')
    >>> atRegex.findall('The cat in the hat sat on the flat mat.')
    ['cat', 'hat', 'sat', 'lat', 'mat']
    
    • 1
    • 2
    • 3

    要记住,句点字符只匹配一个字符

    用点-星匹配所有字符

    句点字符表示“除换行外所有单个字符”,星号字符表示“前面字符出现零次或多次”。在交互式环境中输入以下代码:

    >>> nameRegex = re.compile(r'First Name: (.*) Last Name: (.*)')
    >>> mo = nameRegex.search('First Name: Al Last Name: Sweigart')
    >>> mo.group(1)
    'Al'
    >>> mo.group(2)
    'Sweigart'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    点-星使用“贪心”模式:它总是匹配尽可能多的文本。要用“非贪心”模式匹配所有文本,就使用点-星和问号。

    >>> nongreedyRegex = re.compile(r'<.*?>')
    >>> mo = nongreedyRegex.search('<To serve man> for dinner.>')
    >>> mo.group()
    '<To serve man>'
    >>> greedyRegex = re.compile(r'<.*>')
    >>> mo = greedyRegex.search('<To serve man> for dinner.>')
    >>> mo.group()
    '<To serve man> for dinner.>'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    两个正则表达式都可以翻译成“匹配一个左尖括号,接下来是任意字符,接下来是一个右尖括号”。但是字符串for dinner.>对右肩括号有两种可能的匹配。在非贪心的正则表达式中,Python 匹配最短可能的字符串:<To serve man>。在贪心版本中,Python 匹配最长可能的字符串:<To serve man> for dinner.>

    用句点字符匹配换行

    点-星将匹配除换行外的所有字符。通过传入 re.DOTALL 作为 re.compile()的第二个参数,可以让句点字符匹配所有字符,包括换行字符。

    >>> noNewlineRegex = re.compile('.*')
    >>> noNewlineRegex.search('Serve the public trust.nProtect the innocent.
    nUphold the law.').group()
    'Serve the public trust.'
    >>> newlineRegex = re.compile('.*', re.DOTALL)
    >>> newlineRegex.search('Serve the public trust.nProtect the innocent.nUphold the law.').group()
    'Serve the public trust.nProtect the innocent.nUphold the law.'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    不区分大小写的匹配

    要让正则表达式不区分大小写,可以向re.compile()传入 re.IGNORECASE 或 re.I,作为第二个参数。 在交互式环境中输入以下代码:

    >>> robocop = re.compile(r'robocop', re.I)
    >>> robocop.search('RoboCop is part man, part machine, all cop.').group()
    'RoboCop'
    >>> robocop.search('ROBOCOP protects the innocent.').group()
    'ROBOCOP' 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    用 sub方法替换字符串

    第一个参数是一个字符串,用于取代发现的匹配。第二个参数是一个字符串,即正则表达式。sub()方法返回替换完成后的字符串。例如,在交互式环境中输入以下代码:

    >>> namesRegex = re.compile(r'Agent w+')
    >>> namesRegex.sub('CENSORED', 'Agent Alice gave the secret documents to Agent Bob.')
    'CENSORED gave the secret documents to CENSORED.'
    
    • 1
    • 2
    • 3

    有时候,你可能需要使用匹配的文本本身,作为替换的一部分。在 sub()的第一个参数中,可以输入1、2、3……。表示“在替换中输入分组 1、2、3……的文本”。 例如,假定想要隐去密探的姓名,只显示他们姓名的第一个字母。要做到这一点,可以使用正则表达式Agent (w)w*,传入 r'1****'作为 sub()的第一个参数。字符串中的1 将由分组 1 匹配的文本所替代,也就是正则表达式的(w)分组。

    >>> agentNamesRegex = re.compile(r'Agent (w)w*')
    >>> agentNamesRegex.sub(r'1****', 'Agent Alice told Agent Carol that Agent
    Eve knew Agent Bob was a double agent.')
    A**** told C**** that E**** knew B**** was a double agent.'
    
    • 1
    • 2
    • 3
    • 4
    管理复杂的正则表达式

    忽略正则表达式字符串中的空白符和注释,可以向re.compile()传入变量 re.VERBOSE,作为第二个参数。

    phoneRegex = re.compile(r'''(
     (d{3}|(d{3}))? # area code
     (s|-|.)? # separator
     d{3} # first 3 digits
     (s|-|.) # separator
     d{4} # last 4 digits
     (s*(ext|x|ext.)s*d{2,5})? # extension
     )''', re.VERBOSE)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    请注意,前面的例子使用了三重引号''',创建了一个多行字符串。这样就可以将正则表达式定义放在多行中,让它更可读。

    组合使用 re.IGNOREC ASE、re.DOTALL 和 re.VERBOSE

    可以使用管道字符(|)将变量组合起来,从而绕过这个限制。管道字符在这里称为“按位或”操作符。所以,如果希望正则表达式不区分大小写,并且句点字符匹配换行,就可以这样构造re.compile调用:

    >>> someRegexValue = re.compile('foo', re.IGNORECASE | re.DOTALL)
  • 相关阅读:
    JavaScript对原始数据类型的拆装箱操作
    Javascript继承(原始写法,非es6 class)
    动态作用域与词法作用域
    自行车的保养
    探索JS引擎工作原理 (转)
    C语言提高 (7) 第七天 回调函数 预处理函数DEBUG 动态链接库
    C语言提高 (6) 第六天 文件(续) 链表的操作
    C语言提高 (5) 第五天 结构体,结构体对齐 文件
    C语言提高 (4) 第四天 数组与数组作为参数时的数组指针
    C语言提高 (3) 第三天 二级指针的三种模型 栈上指针数组、栈上二维数组、堆上开辟空间
  • 原文地址:https://www.cnblogs.com/gina11/p/13819389.html
Copyright © 2011-2022 走看看