Python正则中的重复、特殊字符与分组
重复字符
在Python的正则表达式中,重复字符用于指定前面的字符或字符组出现的次数。这些重复字符为我们在匹配复杂字符串模式时提供了极大的灵活性。
基本重复字符
*
:表示前面的字符或字符组可以出现0次或多次。 例如,假设我们要匹配包含零个或多个字母a
的字符串。
import re
pattern = 'a*'
strings = ['', 'a', 'aa', 'aaa']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
在上述代码中,re.search
函数在每个字符串中搜索匹配a*
模式的子串。空字符串匹配,因为a
可以出现0次;包含一个或多个a
的字符串也匹配,因为a
可以出现多次。
+
:表示前面的字符或字符组必须出现1次或多次。 例如,匹配包含一个或多个字母a
的字符串。
import re
pattern = 'a+'
strings = ['', 'a', 'aa', 'aaa']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
这里空字符串不匹配,因为a
至少要出现1次,而包含a
的字符串都匹配。
?
:表示前面的字符或字符组可以出现0次或1次。 例如,匹配包含0个或1个字母a
的字符串。
import re
pattern = 'a?'
strings = ['', 'a', 'aa', 'aaa']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
空字符串和只包含一个a
的字符串匹配,而包含多个a
的字符串不匹配,因为a
最多只能出现1次。
限定重复次数
{n}
:表示前面的字符或字符组必须恰好出现n
次。 例如,匹配恰好包含3个字母a
的字符串。
import re
pattern = 'a{3}'
strings = ['', 'a', 'aa', 'aaa', 'aaaa']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
只有包含3个a
的字符串匹配,其他字符串都不匹配。
{n,}
:表示前面的字符或字符组必须出现n
次或更多次。 例如,匹配包含3个或更多字母a
的字符串。
import re
pattern = 'a{3,}'
strings = ['', 'a', 'aa', 'aaa', 'aaaa']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
包含3个或更多a
的字符串匹配,而包含少于3个a
的字符串不匹配。
{n,m}
:表示前面的字符或字符组必须出现至少n
次,但不超过m
次。 例如,匹配包含2到4个字母a
的字符串。
import re
pattern = 'a{2,4}'
strings = ['', 'a', 'aa', 'aaa', 'aaaa', 'aaaaa']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
包含2到4个a
的字符串匹配,而包含少于2个或多于4个a
的字符串不匹配。
贪婪与非贪婪匹配
在正则表达式中,重复字符默认是贪婪的,即尽可能多地匹配字符。
例如,考虑字符串'aaaaa'
和模式a{2,4}
。贪婪匹配会匹配4个a
,因为它会尝试匹配尽可能多的字符,只要不超过上限。
import re
pattern = 'a{2,4}'
string = 'aaaaa'
match = re.search(pattern, string)
if match:
print(match.group())
输出为aaaa
。
然而,有时我们希望匹配尽可能少的字符,这就是非贪婪匹配。在重复字符后加上?
就可以实现非贪婪匹配。
对于同样的字符串'aaaaa'
和模式a{2,4}?
,非贪婪匹配会匹配2个a
。
import re
pattern = 'a{2,4}?'
string = 'aaaaa'
match = re.search(pattern, string)
if match:
print(match.group())
输出为aa
。
特殊字符
正则表达式中有许多特殊字符,它们具有特定的含义,用于构建复杂的匹配模式。
字符类
[]
:字符类用于匹配方括号内的任意一个字符。 例如,[abc]
匹配a
、b
或c
中的任意一个字符。
import re
pattern = '[abc]'
strings = ['a', 'b', 'c', 'd']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
包含a
、b
或c
的字符串匹配,而包含d
的字符串不匹配。
可以在字符类中使用范围,如[a - z]
匹配任意小写字母,[0 - 9]
匹配任意数字。
import re
pattern = '[a - z]'
strings = ['a', 'Z', '5']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
这里只有小写字母a
匹配,大写字母Z
和数字5
不匹配。
[^]
:取反字符类,匹配不在方括号内的任意一个字符。 例如,[^abc]
匹配除了a
、b
和c
之外的任意字符。
import re
pattern = '[^abc]'
strings = ['a', 'b', 'c', 'd']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
这里只有字符d
匹配,a
、b
和c
不匹配。
预定义字符类
.
:匹配除换行符\n
之外的任意一个字符。 例如,a.c
匹配a
后跟任意一个字符(除\n
)再跟c
的字符串。
import re
pattern = 'a.c'
strings = ['abc', 'a c', 'a1c', 'a\nc']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
abc
、a c
和a1c
匹配,而a\nc
不匹配。
\d
:匹配任意一个数字字符,等价于[0 - 9]
。
import re
pattern = '\d'
strings = ['1', 'a', '5']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
数字1
和5
匹配,字母a
不匹配。
\D
:匹配任意一个非数字字符,等价于[^0 - 9]
。
import re
pattern = '\D'
strings = ['1', 'a', '5']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
字母a
匹配,数字1
和5
不匹配。
\s
:匹配任意一个空白字符,包括空格、制表符、换行符等,等价于[ \t\n\r\f\v]
。
import re
pattern = '\s'
strings = [' ', '\t', 'a']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
空格
和制表符\t
匹配,字母a
不匹配。
\S
:匹配任意一个非空白字符,等价于[^ \t\n\r\f\v]
。
import re
pattern = '\S'
strings = [' ', '\t', 'a']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
字母a
匹配,空格
和制表符\t
不匹配。
\w
:匹配任意一个单词字符,包括字母、数字和下划线,等价于[a - zA - Z0 - 9_]
。
import re
pattern = '\w'
strings = ['a', '1', '_', ' ']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
字母a
、数字1
和下划线_
匹配,空格
不匹配。
\W
:匹配任意一个非单词字符,等价于[^a - zA - Z0 - 9_]
。
import re
pattern = '\W'
strings = ['a', '1', '_', ' ']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
空格
匹配,字母a
、数字1
和下划线_
不匹配。
边界匹配
^
:匹配字符串的开头。 例如,^a
匹配以字母a
开头的字符串。
import re
pattern = '^a'
strings = ['aabc', 'babc']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
aabc
匹配,因为它以a
开头,而babc
不匹配。
$
:匹配字符串的结尾。 例如,c$
匹配以字母c
结尾的字符串。
import re
pattern = 'c$'
strings = ['abc', 'abbc']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
abc
匹配,因为它以c
结尾,而abbc
不匹配。
\b
:匹配单词边界,即单词和非单词字符之间的位置,或者字符串开头或结尾的位置。 例如,\bcat\b
匹配独立的单词cat
,而不是category
中的cat
。
import re
pattern = '\bcat\b'
strings = ['cat', 'category', 'the cat']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
cat
和the cat
中的cat
匹配,而category
中的cat
不匹配。
\B
:匹配非单词边界。 例如,\Bcat\B
匹配不在单词边界的cat
,如category
中的cat
。
import re
pattern = '\Bcat\B'
strings = ['cat', 'category', 'the cat']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
category
中的cat
匹配,而cat
和the cat
中的cat
不匹配。
分组
在正则表达式中,分组是一种强大的功能,它允许我们将多个字符或子模式组合在一起,作为一个整体进行操作。
基本分组
使用圆括号()
来定义分组。例如,(ab)+
表示ab
这个组合可以出现1次或多次。
import re
pattern = '(ab)+'
strings = ['', 'ab', 'abab', 'aab']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
包含一个或多个ab
组合的字符串ab
和abab
匹配,而空字符串和aab
不匹配。
捕获组
捕获组是最常见的分组类型,它会记住匹配的内容。在Python中,可以使用group()
方法来获取捕获组匹配的内容。
例如,假设我们有一个字符串格式为name:age
,我们想分别获取名字和年龄。
import re
pattern = '(\w+):(\d+)'
string = 'John:25'
match = re.search(pattern, string)
if match:
name = match.group(1)
age = match.group(2)
print(f"名字: {name}, 年龄: {age}")
这里(\w+)
是第一个捕获组,匹配名字部分;(\d+)
是第二个捕获组,匹配年龄部分。group(1)
获取第一个捕获组匹配的内容,group(2)
获取第二个捕获组匹配的内容。
非捕获组
有时候我们只是想将一些子模式组合在一起,但不想捕获它们匹配的内容,这时可以使用非捕获组。非捕获组的语法是(?:pattern)
。
例如,(?:ab)+
表示ab
组合出现1次或多次,但不会捕获ab
的匹配内容。
import re
pattern = '(?:ab)+'
string = 'abab'
match = re.search(pattern, string)
if match:
print("匹配成功,但没有捕获组内容")
这里虽然匹配成功,但无法通过group()
方法获取ab
的匹配内容,因为它是非捕获组。
反向引用
反向引用允许我们在正则表达式中引用之前定义的捕获组。语法是\number
,其中number
是捕获组的编号。
例如,假设我们要匹配重复的单词,如word word
。
import re
pattern = '(\w+)\s+\1'
strings = ['hello hello', 'hello world']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
(\w+)
是第一个捕获组,匹配一个单词。\s+
匹配一个或多个空白字符。\1
是反向引用,引用第一个捕获组匹配的内容,所以整个模式匹配重复的单词。因此,hello hello
匹配,而hello world
不匹配。
分组与重复字符的结合
分组可以与重复字符一起使用,以实现更复杂的模式匹配。例如,(abc){2}
表示abc
这个组合必须恰好出现2次。
import re
pattern = '(abc){2}'
strings = ['abcabc', 'abc', 'abcab']
for string in strings:
if re.search(pattern, string):
print(f"'{string}' 匹配成功")
else:
print(f"'{string}' 匹配失败")
只有abcabc
匹配,因为它包含两个abc
组合,而abc
和abcab
不匹配。
通过合理运用重复字符、特殊字符和分组,我们可以在Python正则表达式中构建出极其复杂且强大的匹配模式,满足各种文本处理的需求。无论是数据提取、文本验证还是字符串替换,这些正则表达式的特性都为我们提供了高效的解决方案。在实际应用中,需要根据具体的需求仔细设计正则表达式,同时注意性能和准确性的平衡。例如,在处理大量文本时,过于复杂的正则表达式可能会导致性能下降,因此需要进行优化。此外,对于一些模糊的匹配需求,可能需要结合具体的业务逻辑来确定最合适的正则表达式。同时,在使用捕获组和反向引用时,要确保其逻辑正确,避免出现错误的引用或不必要的捕获,以提高代码的可读性和可维护性。总之,深入理解和熟练运用Python正则表达式中的这些特性,将大大提升我们在文本处理领域的编程能力。