Python 正则表达式使用--Re 模块详解

目录

1. 常用正则表达式符号和特殊字符

 2.  Re 模块:核心函数和方法

2.1 re.compile() 编译函数

2.1.1 re.compile() 语法格式

2.1.2 re.compile() 用法

2.2 re.match() 和 re.search() 匹配和搜索函数

2.2.1 re.match() 语法格式

2.2.2 re.match() 用法

2.2.3 re.search() 语法格式

2.2.4 re.search() 用法

2.3 re.findall() 和 re.finditer() 查找所有符合条件的字符串

2.3.1 re.findall() 语法格式

2.3.2 re.findall() 用法

2.3.3 re.finditer() 语法格式

2.3.4 re.finditer() 用法

2.4 re.split() 分割函数

2.4.1 re.split() 语法结构

2.4.2 re.split() 用法

2.5 re.sub() 和 re.subn() 替换函数

2.5.1 re.sub() 语法结构

2.5.2 re.sub() 用法

2.5.3 re.subn() 语法结构

2.5.4 re.subn() 用法

3. 贪婪模式和非贪婪模式

4. 扩展表示法

4.1 (?iLmsux) 在正则表达式中嵌入一个或者多个特殊"标记"参数

4.1.1 (?i)

4.1.2 (?L)

4.1.3 (?m)

4.1.4 (?s)

4.1.5 (?u)

4.1.6 (?x)

4.2 (?:...) 表示一个匹配不用保存的分组

4.3 (?P...) 由名字 name 标示而不是数字 ID 表示的正则分组

4.3.1 使用数字 ID 表示分组

 4.3.2 使用名字 name 表示分组

4.4 (?P=name)  在正则后面引用前面的组

4.5 (?#comments) 标示注释,所有内容都被忽略

4.6 (?=...) 正向前行匹配,以 ... 字符串结尾才匹配

4.7 (?!...) 负向前行匹配, 不以 ... 字符串结尾才匹配

4.8 (?<=...) 正向后行匹配,之前有 ... 字符串才进行匹配

4.9 (?<!...) 负向后行匹配,之前没有 ... 字符串才进行匹配

4.10 (?(id/name)Y|N) 匹配不同的字符串


1. 常用正则表达式符号和特殊字符

        正则表达式是处理数据时候经常用到的,背景不再赘述。简单说下 Python 中两种模式匹配。

        第一种是搜索 searching,第二种是匹配 matching。

        搜索即在字符串中任意部分搜索匹配的模式,而匹配是是指判断一个字符串能否从起始处全部或者部分的匹配某个模式。

        搜索通过 Re.search() 实现,匹配通过 Re.match() 实现,Re 是 Python 内置的库。

        现在来介绍最常用的元字符 ( metacharacter ) --特殊字符和符号,正是它们赋予了正则表达式强大的功能和灵活性。

正则表达式中最常见的符号

记号说明示范
普通字符串就匹配该字符串的值abc,123,A_B_2
re1|re2匹配正则表达式 re1 或者 re2abc|123,就是 abc 或者 123
.匹配除了换行符之外的任何字符a.b,意味着可以是abb,acb,a2b 等待
^匹配字符串的开始^abc,可以是abcd,abce,但是不能是babc
$匹配字符串的结尾ab$,可以是ab,cab,2ab, 但是不能是abc
*匹配前面出现的正则表达式零次或者多次,该正则表达式可以是单个字符,也可以是()包起来的

a*,可以是aaaaa,或者空字符

(abc)*,可以是abcabcabc,或者空字符

+匹配前面出现的正则表达式1次或者多次,该正则表达式可以是单个字符,也可以是()包起来的

a+,可以是aaaaa,或者a

(abc)+,可以是abcabcabc,或者abc

?

匹配前面出现的正则表达式零次或者1次,该正则表达式可以是单个字符,也可以是()包起来的

a?,可以是a,或者空字符

(abc)?,可以是abc,或者空字符

{N}匹配前面出现的正则表达式 N 次a{4},即aaaa
{M,N}匹配前面出现的正则表达式 M 到 N 次a{2,4},即aa,aaa,aaaa
[....]匹配字符组中出现的任何一个字符[abc] ,即匹配a、b、c
[..X-Y....]匹配从字符 X 到 Y 的任意字符[0-3],即匹配0、1、2、3
[^....]即不匹配此字符集中出现的任何一个字符[^0-3],即匹配除了 0、1、2、3之外的所有字符
(*|+|?|{})?用于上面出现的任何“非贪婪”。版本重复匹配次数符号。这个需要在讲贪婪模式的时候详细讲。
(....)匹配封闭括号中正则表达式,并且保存在子组在讲 re.search/match 等具体函数时候可以详细的讲。

        以上都是正则表达式最最常用的,如果对上面不熟悉,后面的章节可以不看了。

正则表达式-特殊字符

记号示范示范
\d匹配任何数字,等同于[0-9],( \D 是 \d 的反义:非任何数字)abc\de,可以是abc0e、abc1e、abc2e 等
\w匹配任何数字字母字符,等同于[0-9a-zA-Z],( \W 是 \w 的反义:非任何数字字母字符)_\w,即_0..._9,_a..._z,_A..._Z 都可以
\s匹配任何空白符号,等同于[\n\r\t\v\f],(\S 是 \s 的反义字符)ab\sc,可以是"ab c"
\b匹配单词边界,(\B 是 \b 的反义字符)\bThe\b 意味着The,但是不能是 The 开头的字符串
\nn匹配已经保存的子组(需要和(.....)一起使用)在讲 re.search/match 等具体函数时候可以详细的讲。
\c逐一匹配特殊字符c(即,取消它的特殊含义,按照字面上匹配)

如\.,即匹配字符.

如 \\,即匹配字符\

\A匹配字符串的起始\Aabc
\Z

 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串

abc\Z

 \ 

 2.  Re 模块:核心函数和方法

2.1 re.compile() 编译函数

        re.compile 对正则表达式模式 pattern 进行编译,编译后的结果可以用于 re.search、re.match、re.findall 等函数,它并不是必须的,但是它非常有用!

        为什么说不是必须的呢,请看下面的一段代码。可以看出,无论是直接用正则表达式还是编译后再使用,都可以得到一样的结果。

a="abc"
patt="^ab"
res=re.match(patt,a)
print(res.group())
patt=re.compile("^ab")
res=re.match(patt,a)
print(res.group())

        那为什么还要有 re.compile() 这个函数呢,因为性能!

        Python 的代码终究会被编译成字节码,然后才会被解释器执行,如果使用预编译代码会比使用字符串要快,并且我们处理文档时候,往往是一个正则表达式要用很多次,如果直接使用字符串,那么每次都需要重复编译,而直接采用预编译,然后调用预编译结果,则可以快很多。同一个正则表达式被使用得越多越划算。

        希望大家养成这个良好的编程习惯!即使模块函数可能对已经编译的对象进行缓存,还是会节省了查询缓存和使用相同字符串反复调用函数的性能开销。

2.1.1 re.compile() 语法格式

          re.compile(pattern, flags=0)

          pattern 即第一章中提到的正则表达式,flags是可选的,默认为 0。flags 的可选值如下:

  1. .re.I (re.IGNORECASE): 忽略大小写 
  2. .re.M (MULTILINE): 多行模式,改变'^'和'$'的行为 
  3. .re.S (DOTALL): 点任意匹配模式,改变'.'的行为 
  4. .re.L (LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定 
  5. .re.U (UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性 
  6. .re.X (VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入

        上述 flag  可以单独用,也可以一起使用。

2.1.2 re.compile() 用法

        在上一个代码段中就已经显示了,后续也会反复使用,此处不再赘述。

2.2 re.match() 和 re.search() 匹配和搜索函数

2.2.1 re.match() 语法格式

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

         flags 和 re.compile() 中的 flags 用法一致。

         string 即被匹配的字符串。

2.2.2 re.match() 用法

          用一小段代码来演示,match 是从字符串的开始进行匹配的。

#匹配全体Python整型的字符串表示形式的集合
patt=re.compile("^[0-9]+$")
words=["1","23","09","www.XXX.net",\
       "8.0","a2","_d3234","cd"]
for word in words:
    if(re.match(patt,word)):
        print(word)

2.2.3 re.search() 语法格式

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

         flags 和 re.compile() 中的 flags 用法一致。

         string 即被匹配的字符串。

2.2.4 re.search() 用法

        请注意,search 只找到第一个符合条件字符串的就返回了,所以即使被搜索的字符串中还有其他的符合字符串,也被忽略了。

        请注意,此处 match 也好,search 也好,都是返回的一个对象,这个对象有方法 group(),groups(),如果没有找到的时候,返回的是 None 对象。

        group() 方法或者返回所有匹配对象,或者是根据特定要求返回某个特定子组。

        groups() 方法很简单,它返回一个包含唯一或者所有子组的元组,如果正则表达式中没有子组的话,groups() 将返回一个空元组,而 group() 则仍然返回全部匹配对象。

        下面是一个没有子组的代码( 没有使用()来划分子组 )。

# 找出字符串中中包含的 ab 字符串,不区分大小
a="S abc ABC -sfg- dfghdfh abc AB A ABCD ED BA ab Ab aB sgwet"
patt=re.compile("AB",re.I)
res=re.search(patt,a)
print(res.group()) #请注意,此处只找到第一个符合条件的就返回了
print(res.groups()) 

        这是一个有子组的代码,使用了 (),可以看到 group() 返回了全部匹配对象,而 groups() 则返回各自的子组。

# 找出字符串中中包含的 abcde 字符串,不区分大小
a="S abc ABC -sfg- dfghdfh abc AB A ABCDE ED BA ab Ab aB sgwet"
patt=re.compile("(AB)c(DE)",re.I)
res=re.search(patt,a)
print(res.group()) #请注意,此处只找到第一个符合条件的就返回了
print(res.groups()) 

        另外,返回对象中可能有用的 .start() 和 .end() 方法,返回匹配对象起始地址和截止地址。

words=["abcom"]
patt=re.compile("^abcom")
for word in words:
    res=re.search(patt,word)
    if(res is not None):
        print(res) # 返回的是一个 re.Match 对象
        print(res.group()) # 返回全部匹配对象
        print(res.groups()) # 返回子组,如果有的话,没有则返回空()
        print(res.start()) #返回匹配对象起始地址
        print(res.end()) #返回匹配对象截至地址

2.3 re.findall() 和 re.finditer() 查找所有符合条件的字符串

2.3.1 re.findall() 语法格式

    re.findall(pattern, string, flags=0)
    flags 和 re.compile() 中的 flags 用法一致。
    string 即被匹配的字符串。

2.3.2 re.findall() 用法

          re.findall 可以查找出所有的符合要求的字符串,并且返回一个列表

         下面这段代码描述了四种常见的情况。

# 找出字符串中中包含的 abcde 字符串,不区分大小
a="S abc ABC -sfg- dfghdfh abc AB A ABCDE ED BABcdedf ab Ab aB sgwet"
#没有子组
patt=re.compile("ABcDE",re.I)
res=re.findall(patt,a)
# 请注意,此处没有 group()、groups() 对象,因为返回的是列表。
# 因为没有子组,返回的是全部对象的列表
print(res)  

#此处有子组
patt=re.compile("(AB)c(DE)",re.I)
res=re.findall(patt,a)
# 请注意,此处没有 group()、groups() 对象,因为返回的是列表。
# 因为有子组,返回的包含子组元组的列表,而不是全部对象的列表
print(res)  

#此处有子组,并且把整个字符串用()包括起来了
patt=re.compile("((AB)c(DE))",re.I)
res=re.findall(patt,a)
# 请注意,此处没有 group()、groups() 对象,因为返回的是列表。
# 因为有子组,且把整个字符串用()包括起来了
#所以返回的包含全部匹配对象、各个子组元组的列表,而不是全部对象的列表
print(res)  


#此处有子组,子组里面还有子组,并且把整个字符串用()包括起来了
patt=re.compile("((A(B))c(DE))",re.I)
res=re.findall(patt,a)
# 请注意,此处没有 group()、groups() 对象,因为返回的是列表。
# 因为有子组,且把整个字符串用()包括起来了
#所以返回的包含全部匹配对象、各个子组元组的列表,而不是全部对象的列表
print(res)  

2.3.3 re.finditer() 语法格式

          re.finditer(pattern, string, flags=0)
          flags 和 re.compile() 中的 flags 用法一致。
          string 即被匹配的字符串。

         re.finditer() 和 re.findall() 非常相似,只不过返回的是一个迭代器,而不是列表,对于每个匹配返回一个匹配对象(re.match 匹配对象)。所以读取方式有了变化,这样内存会更加友好。

2.3.4 re.finditer() 用法

          将 re.findall 函数的用法处代码稍微改一下。

# 找出字符串中中包含的 abcde 字符串,不区分大小
a="S abc ABC -sfg- dfghdfh abc AB A ABCDE ED BABcdedf ab Ab aB sgwet"
#没有子组
patt=re.compile("ABcDE",re.I)
res=re.finditer(patt,a)
# 请注意,此处没有 group()、groups() 对象,因为返回的是列表。
# 因为没有子组,返回的是全部对象的迭代器
print("*"*28)
for tmp in res:
    print(tmp)
    print(tmp.group())
    print(tmp.groups())

#此处有子组
patt=re.compile("(AB)c(DE)",re.I)
res=re.finditer(patt,a)
# 请注意,此处没有 group()、groups() 对象,因为返回的是迭代器。
# 因为有子组,返回的包含子组元组的迭代器,而不是全部对象的迭代器
print("*"*28)
for tmp in res:
    print(tmp)
    print(tmp.group())
    print(tmp.groups())

#此处有子组,并且把整个字符串用()包括起来了
patt=re.compile("((AB)c(DE))",re.I)
res=re.finditer(patt,a)
# 请注意,此处没有 group()、groups() 对象,因为返回的是迭代器。
# 因为有子组,且把整个字符串用()包括起来了
#所以返回的包含全部匹配对象、各个子组元组的迭代器,而不是全部对象的迭代器
print("*"*28)
for tmp in res:
    print(tmp)
    print(tmp.group())
    print(tmp.groups())


#此处有子组,子组里面还有子组,并且把整个字符串用()包括起来了
patt=re.compile("((A(B))c(DE))",re.I)
res=re.finditer(patt,a)
# 请注意,此处没有 group()、groups() 对象,因为返回的是迭代器。
# 因为有子组,且把整个字符串用()包括起来了
#所以返回的包含全部匹配对象、各个子组元组的迭代器,而不是全部对象的迭代器
print("*"*28)
for tmp in res:
    print(tmp)  
    print(tmp.group())
    print(tmp.groups())

  

2.4 re.split() 分割函数

         大家肯定用过 str.split(), re.split()功能更加强大,因为它被设计出来时候就是可以使用正则表达式的。

2.4.1 re.split() 语法结构

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

          flags 和 re.compile() 中的 flags 用法一致。
          string 即被匹配的字符串。

          maxsplit 是最多能被分割的次数,从左而右计算。

          re.split() 返回一个列表。

2.4.2 re.split() 用法

         可以看到下面这段代码,虽然剩下的代码还可以分割,但是因为限制了分割的次数,也不再分割。

a="das:fgfd:dfdgf:dadf"
res=re.split(":",a,2)
res

2.5 re.sub() 和 re.subn() 替换函数

2.5.1 re.sub() 语法结构

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

         flags 和 re.compile() 中的 flags 用法一致。

         repl 即用来替换的字符串

         string 即被替换的字符串。

         count 即被替换的次数,为 0 时候意味着全部替换。

          re.sub()返回被替换后的字符串

2.5.2 re.sub() 用法

# 找出字符串中中包含的 ab 字符串,不区分大小,并且用 XY 来替换
a="S abc ABC -sfg- dfghdfh abc AB A ABCDE ED BABcdedf ab Ab aB sgwet"
#没有子组
patt=re.compile("AB",re.I)
res=re.sub(patt,"XY",a)
# 请注意,此处返回的是字符串
print(res)

2.5.3 re.subn() 语法结构

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

         flags 和 re.compile() 中的 flags 用法一致。

         repl 即用来替换的字符串

         string 即被替换的字符串。

         count 即被替换的次数,为 0 时候意味着全部替换。

          re.sub()返回一个元组,第一个元素是被替换后的字符串,第二个元素是被替换次数的数值。

2.5.4 re.subn() 用法

# 找出字符串中中包含的 ab 字符串,不区分大小,并且用 XY 来替换
a="S abc ABC -sfg- dfghdfh abc AB A ABCDE ED BABcdedf ab Ab aB sgwet"
#没有子组
patt=re.compile("AB",re.I)
res=re.subn(patt,"XY",a)
# 请注意,此处返回的是字符串和替换次数的列表
print(res)

3. 贪婪模式和非贪婪模式

        给大家看下面一小段代码,想在一串字符串中找出连续的数字字符,1 个或者多个都可以。结果是找出了最长的那个符合要求的。这就是贪心匹配,也叫贪婪模式,Python 中默认的模式,在从左到右的顺序中求值时候,尽可能的抓取满足匹配的最长的字符。

        在使用 "*","+",或者"?" 取长度不确定的字符串时候,都会遇到这种情况。

# 找出连续的数字字符,1 个或者多个
a="0123456789"
patt=re.compile("\d+") 
res=re.search(patt,a)
# 请注意,此处返回的是匹配对象
print(res)
print(res.group())
print(res.groups())

        如果不想要贪婪模式,只要最短的满足条件的字符串,可以在"*","+",或者"?" 后面使用 “?” 来使用非贪婪模式。

4. 扩展表示法

4.1 (?iLmsux) 在正则表达式中嵌入一个或者多个特殊"标记"参数

        之前在说re.compile 、re.match、re.search 等函数,提到了模型 pattern 里面配套使用的 flags。其实,除了re.compile 、re.match、re.search 函数中使用 flags 选项,还可以直接在正则表达式中使用类似的功能,即扩展表达式。常见的有(?iLmsux),下面会一一慢慢说。

        首先请注意, (?iLmsux) 只能在正则表达式的开头使用;并且 (?imx)   正则表达式包含三种可选标志:i, m, 或 x ,只影响括号中的区域;(?-imx)    正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。

4.1.1 (?i)

          首先,(?i) 表示 re.I/IGNORECASE,忽略大小写;

words=["abcom","abco","abCoMD","ABCOM","BDAbcOM"]
#patt=re.compile("(?iabcom)")
for word in words:
    res=re.search(r"(?i)abcom",word)
    if(res is not None):
        print("*"*20)
        print(word)
        print(res.group())
        print(res.groups())

4.1.2 (?L)

          等同re.l,re.LOCALE, 表示字符集本地化。即使预定字符类 \w \W \b \B \s \S 取决于当前区域设定 。

        这个功能是为了支持多语言版本的字符集使用环境的,比如在转义符\w,在英文环境下,它代表[a-zA-Z0-9_],即所以英文字符和数字。如果在一个法语环境下使用,缺省设置下,不能匹配"é" 或 “ç”。加上这L选项和就可以匹配了。不过这个不适用于中文环境,将会在第五小节讲如何匹配中文字符。

4.1.3 (?m)

        等同于 re.M ,即多行模式;

word='''
This line is the first abcom,
another line ABCOM,
that line, it's the bestABcomm
'''

res=re.findall(r"(?im)(^th[\w\s]+)",word)
if(res is not None):
    print(res)

  

4.1.4 (?s)

        表示符号 . 可以代表任意符号(正常情况符号 . 表示除 \n 之外的任意符号);等同于.re.S (DOTALL)。用下面的代码,就可以清晰的看出使用 (?s) 和不使用直接的差异了。

word='''
This line is the first abcom,
another line ABCOM,
that line, it's the bestABcomm
'''

res=re.findall(r"(?is)(th.*)",word)
if(res is not None):
    print(res)
res=re.findall(r"(?i)(th.*)",word)
if(res is not None):
    print(res)

  

4.1.5 (?u)

        等同re.U,re.UNICODE,使用 \w, \W, \b, \B 这些元字符时将按照 UNICODE 定义的属性.

4.1.6 (?x)

        等同于 re.X ,冗长模式,允许编写更友好的正则表达式。

4.2 (?:...) 表示一个匹配不用保存的分组

        用下面这段代码来看,当使用 re.search 函数时候,如果使用了 (?:...) 语法,那么返回的对象使用 .groups() 方法时候,则不会体现那个子组。

word="I am happy now, let's have a happy day! If you are not happy, please do not tell me!"

res = re.search(r'(?:happy)\s\w{3,4}', word)
if(res is not None):
    print("*"*40)
    print(res)
    print(res.group())
    print(res.groups())
    print(res.groups(1))
    
res = re.search(r'(happy)\s\w{3,4}', word)
if(res is not None):
    print("*"*40)
    print(res)
    print(res.group())
    print(res.groups())
    print(res.groups(1))

        再看一个复杂一点的例子 

        当不使用 (?:) 时候

word="I am happy now! let's have a happy day! "
    
res = re.search(r'((?:happy)\s(\w+))!', word)
if(res is not None):
    print("-"*40)
    print(res)
    print("res.group()",res.group())
    print("res.groups()",res.groups()) #显示所有子组
    print("res.group(0)",res.group(0))  #显示全部匹配对象
    print("res.group(1)",res.group(1)) #显示第一个()包括的对象
    #显示第二个()包括的对象,越过了(?:)分组,直接到(\w+)
    print("res.group(2)",res.group(2)) 
    #虽然有第三个(),但是因为(?:)分组不保存,所以实际只有两个分组
    print("res.group(3)",res.group(3)) 
    print("res.group(4)",res.group(4)) #这一行其实执行不到

但是使用了(?:)后,子组少了一个 

word="I am happy now! let's have a happy day! "
    
res = re.search(r'((?:happy)\s(\w+))!', word)
if(res is not None):
    print("-"*40)
    print(res)
    print("res.group()",res.group())
    print("res.groups()",res.groups()) #显示所有子组
    print("res.group(0)",res.group(0))  #显示全部匹配对象
    print("res.group(1)",res.group(1)) #显示第一个()包括的对象
    #显示第二个()包括的对象,越过了(?:)分组,直接到(\w+)
    print("res.group(2)",res.group(2)) 
    #虽然有第三个(),但是因为(?:)分组不保存,所以实际只有两个分组
    print("res.group(3)",res.group(3)) 
    print("res.group(4)",res.group(4)) #这一行其实执行不到

4.3 (?P<name>...) 由名字 name 标示而不是数字 ID 表示的正则分组

4.3.1 使用数字 ID 表示分组

        一般我们可以用数字来表示各种分组。如下:

word="I am happy now! let's have a happy day! "
    
res = re.search(r'((happy)\s(\w+))!', word)
if(res is not None):
    print("-"*40)
    print(res)
    print("res.group()",res.group())
    print("res.groups()",res.groups()) #显示所有子组
    print("res.group(0)",res.group(0))  #显示全部匹配对象
    print("res.group(1)",res.group(1)) #显示第一个()包括的对象
    print("res.group(2)",res.group(2)) #显示第二个()包括的对象
    print("res.group(3)",res.group(3)) #显示第三个()包括的对象
    print("res.group(4)",res.group(4)) #因为没有第四个(),所以会报错

       

使用数字 ID 表示分组的规律如下:

  1. 分组组从 0 开始编号
  2. 分组 0 始终存在,表示整个正则表达式的匹配对象
  3. 匹配对象方法.groups() 以 0 为默认参数,等同于. group()
  4. 分组从左到右 从 1 向上编号,分组也可以嵌套,第 n 个 ( 对应的就是第 n 个分组。

 4.3.2 使用名字 name 表示分组

        我们还可以用(?P<name>...) 来取代数字ID。

word="I am happy now! let's have a happy day! "    
res = re.search(r'((?P<NAME>happy)\s(\w+)!)', word)
if(res is not None):
    print("-"*40)
    print(res)
    print("res.group()",res.group())
    print("res.groups()",res.groups()) #显示所有子组
    print("res.group(0)",res.group(0))  #显示全部匹配对象
    print("res.group(1)",res.group(1)) #显示第一个()包括的对象
    print("res.group(2)",res.group(2)) #显示第二个()包括的对象
    print("res.group(3)",res.group(3)) #显示第三个()包括的对象
    #显示 NAME 表示的对象,即和 res.group(2) 的结果为同一个
    print("res.group('NAME')",res.group('NAME')) 
    print("res.group(4)",res.group(4)) #因为没有第四个(),所以会报错

4.4 (?P=name)  在正则后面引用前面的组

         在同一个字符串中匹配由(?P<name)分组的之前文本,可以使用 (?P=name)。

         请注意,此处 pattern 中的 (?P=name) 是为了匹配前面的分组内容,而不是继续分组,所以不视同有效的 (),不会列入数字 ID 的计数中。

        用 (?P<name)、 (?P=name)的好处很明显,相对于数字 ID 方式,它不容易出错。

         下面用代码来表示:

word="I am happy now! let's have a happy day! "    
res = re.search(r'((?P<NAME>happy)\s(\w+)!.*(?P=NAME))', word)
if(res is not None):
    print("-"*40)
    print(res)
    print("res.group()",res.group())
    print("res.groups()",res.groups()) #显示所有子组
    print("res.group(0)",res.group(0))  #显示全部匹配对象
    print("res.group(1)",res.group(1)) #显示第一个()包括的对象
    print("res.group(2)",res.group(2)) #显示第二个()包括的对象
    print("res.group(3)",res.group(3)) #显示第三个()包括的对象
    #显示 NAME 表示的对象,即和 res.group(2) 的结果为同一个
    print("res.group('NAME')",res.group('NAME')) 
    #请注意,此处pattern 虽然有第四个(),但是第四个() 是为了匹配前面的分组内容,
    #而不是继续分组,所以不视同有效的()。因为没有有效的第四个(),所以会报错
    print("res.group(4)",res.group(4)) 

4.5 (?#comments) 标示注释,所有内容都被忽略

        请注意,此处 pattern 中的 (?#comments) 是为了标示注释,所有内容都被忽略,所以不视同有效的 (),不会列入数字 ID 的计数中。

word="I am happy now! let's have a happy day! "    
res = re.search(r'((?#comments-happy)\s(\w+)!)', word)
if(res is not None):
    print("-"*40)
    print(res)
    print("res.group()",res.group())
    print("res.groups()",res.groups()) #显示所有子组
    print("res.group(0)",res.group(0))  #显示全部匹配对象
    print("res.group(1)",res.group(1)) #显示第一个()包括的对象
    print("res.group(2)",res.group(2)) #显示第二个()包括的对象
    
    #请注意,此处pattern 虽然有第三个(),但是(?#comments-happy) 是为了注释,
    #而不是实际分组,所以不视同有效的()。因为总共只有两个有效的(),所以提取res.groups(3)会报错
    print("res.group(3)",res.group(3)) 

4.6 (?=...) 正向前行匹配,以 ... 字符串结尾才匹配

         匹配条件是如果...出现在之后的位置,才进行匹配输入字符串,(?=...) 中的 ... 不参与分组 ;又称作正向前视断言。

        举例说明:

word="I am happy now! let's have a happy day! "    
res = re.search(r'(\s(\w+)!(?=\s\w{1,3}))', word)
if(res is not None):
    print("-"*40)
    print(res)
    print("res.group()",res.group())
    print("res.groups()",res.groups()) #显示所有子组
    print("res.group(0)",res.group(0))  #显示全部匹配对象
    print("res.group(1)",res.group(1)) #显示第一个()包括的对象
    print("res.group(2)",res.group(2)) #显示第二个()包括的对象
    
    #请注意,此处pattern 虽然有第三个(),但是(?=\s\w{1,3})) 是为了正向前行匹配,
    #而不是实际分组,所以不视同有效的()。因为总共只有两个有效的(),所以提取res.groups(3)会报错
    print("res.group(3)",res.group(3)) 

 

4.7 (?!...) 负向前行匹配, 不以 ... 字符串结尾才匹配

        匹配条件是如果 ... 出现在之后的位置,才进行匹配输入字符串,(?!...) 中的 ... 不参与分组 ;又称作负向前视断言

word="I am happy now! let's have a happy day! "    
res = re.search(r'(\s(\w+)!(?!\s\w{1,3}))', word)
if(res is not None):
    print("-"*40)
    print(res)
    print("res.group()",res.group())
    print("res.groups()",res.groups()) #显示所有子组
    print("res.group(0)",res.group(0))  #显示全部匹配对象
    print("res.group(1)",res.group(1)) #显示第一个()包括的对象
    print("res.group(2)",res.group(2)) #显示第二个()包括的对象
    
    #请注意,此处pattern 虽然有第三个(),但是(?!\s\w{1,3}) 是为了负向前行匹配,
    #而不是实际分组,所以不视同有效的()。因为总共只有两个有效的(),所以提取res.groups(3)会报错
    print("res.group(3)",res.group(3)) 

 

4.8 (?<=...) 正向后行匹配,之前有 ... 字符串才进行匹配

        匹配条件是如果 ... 出现在之前的位置,才进行匹配;称作正向后视断言。(?<...) 中的 ... 不参与分组。请注意,Python 不支持可变长度的正向后视断言,会报错:“error: look-behind requires fixed-width pattern”。

word="I am happy now! let's have a happy day! "    
res = re.search(r'((?<=\w{5})\s(\w+)!)', word)
if(res is not None):
    print("-"*40)
    print(res)
    print("res.group()",res.group())
    print("res.groups()",res.groups()) #显示所有子组
    print("res.group(0)",res.group(0))  #显示全部匹配对象
    print("res.group(1)",res.group(1)) #显示第一个()包括的对象
    print("res.group(2)",res.group(2)) #显示第二个()包括的对象
    
    #请注意,此处 pattern 虽然有第三个(),但是(?<=\w{5}) 是为了正向后视断言,
    #而不是实际分组,所以不视同有效的()。因为总共只有两个有效的(),所以提取res.groups(3)会报错
    print("res.group(3)",res.group(3)) 

4.9 (?<!...) 负向后行匹配,之前没有 ... 字符串才进行匹配

        匹配条件是如果 ... 不出现在之前的位置,而不使用输入字符串;称作负向后视断言(?<!192\.168\.)

        匹配条件是如果 ... 出现在之前的位置,才进行匹配;又称作负向后视断言。(?<!...) 中的 ... 不参与分组。请注意,Python 不支持可变长度的负向后视断言,会报错:“error: look-behind requires fixed-width pattern”。

word="I am happy now! let's have a happy day! "    
res = re.search(r'((?<!\w{5})\s(happy day))', word)
if(res is not None):
    print("-"*40)
    print(res)
    print("res.group()",res.group())
    print("res.groups()",res.groups()) #显示所有子组
    print("res.group(0)",res.group(0))  #显示全部匹配对象
    print("res.group(1)",res.group(1)) #显示第一个()包括的对象
    print("res.group(2)",res.group(2)) #显示第二个()包括的对象
    
    #请注意,此处 pattern 虽然有第三个(),但是(?<!\w{5})是为了负向后视断言,
    #而不是实际分组,所以不视同有效的()。因为总共只有两个有效的(),所以提取res.groups(3)会报错
    print("res.group(3)",res.group(3)) 

4.10 (?(id/name)Y|N) 匹配不同的字符串

        如果分组所提供的 id 或者 name 存在,对于给出的 id 或者 name,先尝试去匹配 部分的内容;如果 id 或 name 条件不满足,则去匹配 N 部分的内容;|N是可选项。

word="I am happy now! let's have a happy day! "    
res = re.search(r'((?P<NAME>Happy|happy)\s(\w+)!)', word)
if(res is not None):
    print("-"*40)
    print(res)
    print("res.group()",res.group())
    print("res.groups()",res.groups()) #显示所有子组
    print("res.group(0)",res.group(0))  #显示全部匹配对象
    print("res.group(1)",res.group(1)) #显示第一个()包括的对象
    print("res.group(2)",res.group(2)) #显示第二个()包括的对象
    print("res.group(3)",res.group(3)) #显示第三个()包括的对象
    #显示 NAME 表示的对象,即和 res.group(2) 的结果为同一个
    print("res.group('NAME')",res.group('NAME')) 
    print("res.group(4)",res.group(4)) #因为没有第四个(),所以会报错

'''

要是大家觉得写得还行,麻烦点个赞或者收藏吧,最好加关注我,想个博客涨涨人气,非常感谢!

'''

  • 19
    点赞
  • 123
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
### 回答1: 好的,我可以回答你关于Python正则表达式的问题。 Python正则表达式是一种用来匹配和处理字符串的工具。它可以在字符串中搜索和匹配特定的模式,以实现更高效和精确的数据处理。Python的re模块提供了完整的正则表达式支持,并且非常强大和灵活。 使用Python正则表达式,你可以实现各种字符串操作,比如搜索、替换、分割、提取等等。它的语法相对简单,但是功能非常强大,可以满足大部分的字符串处理需求。 在使用Python正则表达式时,你需要掌握一些基本的语法规则,比如元字符、字符集、重复、分组等等。这些语法规则可以组合在一起,形成复杂的匹配模式,以实现更加精细的字符串处理。 总之,Python正则表达式是一种非常有用的工具,可以大大提高字符串处理的效率和精确度。如果你想深入了解它的用法和技巧,可以查看Python官方文档中关于re模块的详细说明。 ### 回答2: Python正则表达式是一种强大的文本匹配和处理工具,通过使用特定的模式来识别和操作文本中的字符串。正则表达式通常被用于从文本中提取特定的信息、验证输入的有效性、进行替换或搜索等操作。 Python正则表达式的语法使用元字符和特殊字符来定义搜索模式,其中元字符用于描述字符类型或位置,特殊字符用于描述重复次数或匹配方式。常见的元字符包括"."(匹配任意字符)、"\d"(匹配数字字符)、"\w"(匹配字母、数字或下划线字符)、"\s"(匹配空白字符)等。特殊字符包括"*"(匹配前面的模式0次或多次)、"+"(匹配前面的模式1次或多次)、"?"(匹配前面的模式0次或1次),以及花括号{}(指定前面模式的重复次数)等。 使用Python正则表达式时,常见的操作包括匹配、搜索、替换和分割。匹配操作通过`re.match()`或`re.search()`函数实现,用于从字符串的起始位置或任意位置开始匹配;搜索操作通过`re.findall()`或`re.finditer()`函数实现,用于在整个字符串中搜索匹配的内容;替换操作通过`re.sub()`函数实现,用于替换匹配到的内容;分割操作通过`re.split()`函数实现,用于按指定的模式分割字符串。 Python正则表达式还支持分组、捕获、非捕获、反向引用等高级特性,可通过使用括号`()`进行分组,并使用`\number`的方式引用分组匹配到的内容。 总而言之,Python正则表达式提供了一套强大且灵活的工具来处理文本匹配和处理的需求。学习和熟练掌握正则表达式使用,对于处理和分析文本数据将大有裨益。 ### 回答3: Python正则表达式是一种用来匹配字符串模式的工具。它使用一种特殊的语法来描述字符串的模式,然后通过与给定的字符串进行比较,判断是否匹配。 在Python中,我们使用re模块使用正则表达式。首先,我们需要导入re模块,然后使用re模块提供的函数来进行匹配操作。 正则表达式中的一些基本概念包括: 1. 字符组:用方括号[]表示,表示匹配其中的任意一个字符。例如[abc]表示匹配字符a、b或c。 2. 量词:用来表示匹配多个字符的数量。例如*表示匹配0个或多个字符,+表示匹配1个或多个字符,?表示匹配0个或1个字符。 3. 元字符:具有特殊含义的字符,例如.表示匹配除换行符外的任意字符,\d表示匹配任意一个数字字符。 4. 转义字符:使用反斜杠\来转义元字符。例如\.表示匹配点字符。 5. 边界匹配:^表示匹配字符串的开头,$表示匹配字符串的结尾。 可以通过这些基本概念进行复杂模式的匹配。例如,使用re模块的match函数可以判断一个字符串是否以某个模式开头,使用search函数可以在字符串中搜索匹配某个模式的子串,使用findall函数可以找到所有匹配的子串。 除了基本概念外,Python正则表达式还提供了一些更高级的功能,例如分组、捕获和替换等。 总之,Python正则表达式是一种强大的工具,可以用于字符串的匹配和处理。掌握正则表达式的基本语法和常用函数,可以帮助我们更高效地处理字符串操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江南野栀子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值