Python3 正则表达式

match 与 search 的区别、检索替换、Pattern 对象、修饰符与常用模式。

Intermediate
Key Pointsmatch 只从开头匹配、search 全文查找;频繁使用的模式先 compile 复用;分组用 () 取值。

re.match 函数

re.match(pattern, string) tries to match at the start of the string, returning a Match object on success and None on failure. It does not need to reach the end — a match at position 0 is enough.

Python
import re

print(re.match('www', 'www.runoob.com').span())
print(re.match('com', 'www.runoob.com'))
print(re.match(r'(\d{4})-(\d{2})', '2024-10-31').groups())
print(re.match(r'(\d{4})-(\d{2})', '2024-10-31').group(1))
Output
(0, 3)
None
('2024', '10')
2024

re.search 方法

re.search(pattern, string) scans the whole string and returns the first match wherever it occurs. Position is irrelevant — that is the essential difference from match.

Python
import re

print(re.search('www', 'www.runoob.com').span())
print(re.search('com', 'www.runoob.com').span())
print(re.search(r'\d+', 'abc123def456').group())
print(re.search(r'(?P<k>\w+)=(?P<v>\d+)', 'a=1 b=22').groupdict())
print(re.findall(r'(?P<k>\w+)=(?P<v>\d+)', 'a=1 b=22'))
Output
(0, 3)
(11, 14)
123
{'k': 'a', 'v': '1'}
[('a', '1'), ('b', '22')]

re.match 与 re.search 的区别

In one line: match only looks at the start, search scans anywhere. Use re.fullmatch() when the whole string must match; search is the right tool for "does this text contain X".

Python
import re

line = "Cats are smarter than dogs"

m = re.match(r'(.*) are (.*?) .*', line, re.M | re.I)
if m:
    print("group():", m.group())
    print("group(1):", m.group(1))
    print("group(2):", m.group(2))

print(re.match('dogs', line))
print(re.search('dogs', line).span())
print(re.fullmatch(r'\d+', '123'), re.fullmatch(r'\d+', '123a'))
Output
group(): Cats are smarter than dogs
group(1): Cats
group(2): smarter
None
(22, 26)
<re.Match object; span=(0, 3), match='123'> None

检索和替换

re.sub(pattern, repl, string, count=0) replaces matches; repl may be a string, a function, or a group reference like \1. re.subn() also returns the count, and re.split() cuts by pattern.

Python
import re

print(re.sub(r'\d+', '*', 'abc123def456'))
print(re.sub(r'\d+', '*', 'abc123def456', count=1))

def double(m):
    return str(int(m.group()) * 2)

print(re.sub(r'\d+', double, 'abc123def456'))
print(re.subn(r'\d+', '#', 'a1b22c333'))
print(re.sub(r'(\w+) (\w+)', r'\2 \1', 'hello world'))
print(re.split(r'\s+', 'a  b\tc'))
Output
abc*def*
abc*def456
abc246def912
('a#b#c#', 3)
world hello
['a', 'b', 'c']

正则表达式对象

re.compile(pattern, flags) pre-compiles a pattern into a reusable Pattern object. When the same pattern is used repeatedly, compiling once is faster and clearer; the object exposes match / search / findall directly.

Python
import re

p = re.compile(r'(\w+)@(\w+)\.com')
m = p.match('tom@example.com')

print(m.group(0), m.group(1), m.group(2))
print(m.groups())
print(m.start(), m.end(), m.span())
print(p.findall('a@x.com b@y.com'))
print(p.pattern)
print(p.flags)
Output
tom@example.com tom example
('tom', 'example')
0 15 (0, 15)
[('a', 'x'), ('b', 'y')]
(\w+)@(\w+)\.com
32

正则表达式修饰符 - 可选标志

Flags alter matching: re.I ignores case, re.M makes ^/$ per-line, re.S lets . match newlines, re.X allows comments and whitespace in the pattern. Combine with |.

FlagMeaning
re.IIgnore case
re.M^ and $ match at line boundaries
re.S. matches newline too
re.XVerbose mode: whitespace ignored, # comments
re.AASCII-only matching for \w, \b
Python
import re

print(bool(re.match('python', 'Python')))
print(bool(re.match('python', 'Python', re.I)))

text = "line1\nline2"
print(bool(re.search(r'^line2', text)))
print(bool(re.search(r'^line2', text, re.M)))

print(bool(re.match(r'a.b', 'a\nb')))
print(bool(re.match(r'a.b', 'a\nb', re.S)))

pattern = '''
    \d+   # integer part
    \.    # decimal point
    \d+   # fraction part
'''
print(bool(re.match(pattern, '3.14', re.X)))
Output
False
True
False
True
False
True
True

正则表达式模式

The pattern grammar is the common base of every regex dialect: . any char, * + ? quantifiers, {m,n} counts, [] sets, () groups, | alternation, ^ $ anchors, \d \w \s classes, \b word boundary.

PatternMatches
^Start of string (or line with re.M)
$End of string (or line with re.M)
.Any character except newline
[abc]One of a, b, c
[^abc]Any character but a, b, c
re*Zero or more repetitions
re+One or more repetitions
re?Zero or one repetition
re{2,4}Two to four repetitions
\d / \DDigit / non-digit
\w / \WWord char / non-word char
\bWord boundary
Python
import re

print(re.findall(r'^a', 'abc\nabc', re.M))
print(re.findall(r'a.c', 'abc adc a-c'))
print(re.findall(r'a[bc]c', 'abc acc axc'))
print(re.findall(r'ab*', 'a ab abb abbb'))
print(re.findall(r'\bcat\b', 'cat cats concat'))
print(re.findall(r'\d{2,3}', '1 22 333 4444'))
print(re.findall(r'(ab)+', 'ababab ab'))
Output
['a', 'a']
['abc', 'adc', 'a-c']
['abc', 'acc']
['a', 'ab', 'abb', 'abbb']
['cat']
['22', '333', '444']
['ab', 'ab']

正则表达式实例

These are the patterns you meet most in practice: phone validation, stripping HTML tags, splitting on whitespace, and named-group extraction. Rule of thumb: regex is for extraction and validation, not for parsing nested structures.

Python
import re

text = "联系 13800138000 或 13912345678"
print(re.findall(r'1[3-9]\d{9}', text))

html = '<b>bold</b>'
print(re.sub(r'<[^>]+>', '', html))

m = re.match(r'(?P<year>\d{4})-(?P<month>\d{2})', '2024-10')
print(m.group('year'), m.group('month'), m.groupdict())

log = '2024-10-31 12:00:00 ERROR disk full'
mm = re.match(r'(\S+) (\S+) (\w+) (.+)', log)
print(mm.group(3), '|', mm.group(4))
Output
['13800138000', '13912345678']
bold
2024 10 {'year': '2024', 'month': '10'}
ERROR | disk full
Parsing HTML/XML/JSON with regex is a classic mistake — nesting and escaping make patterns explode. Use html.parser, xml.etree or json instead.

Friends & Partners