Chapter 06 / 10

标志位与多行模式

用标志位改变正则引擎的匹配行为——大小写、全局、多行、DOTALL

正则标志位(Flags)

标志位修改正则引擎的默认行为。JavaScript 在正则字面量的结束斜杠后写标志:/pattern/flags;Python 在 re.compile() 或函数调用中传入常量。

标志PythonJS含义
忽略大小写re.IGNORECASE / re.Ii大小写不敏感匹配
全局匹配(用 findall/finditer)g找出所有匹配(非首个)
多行模式re.MULTILINE / re.Mm^ $ 匹配每行首尾
点号全匹配re.DOTALL / re.Ss. 也匹配换行符
详细模式re.VERBOSE / re.X允许空格和注释
Unicodere.UNICODE / re.Uu启用 Unicode 匹配
粘滞匹配y从 lastIndex 位置精确匹配

忽略大小写(i)

# Python
re.findall(r'python', 'Python PYTHON python', re.IGNORECASE)
# → ['Python', 'PYTHON', 'python']

// JavaScript
'Hello World'.match(/hello/gi)  // → ['Hello']

多行模式(m)

默认情况下,^$ 匹配整个字符串的首尾。开启多行模式后,它们匹配每一行的首尾:

text = """第一行
第二行
第三行"""

# 默认:只匹配字符串起始
re.findall(r'^\S+', text)
# → ['第一行']

# 多行模式:匹配每行起始
re.findall(r'^\S+', text, re.MULTILINE)
# → ['第一行', '第二行', '第三行']
/^\d+/gm(多行)
1. 苹果
2. 香蕉
3. 橙子
多行模式下 ^ 匹配每行行首

DOTALL 模式(s)

. 也能匹配换行符,适合处理跨行内容:

# 提取多行注释
re.findall(r'/\*.*?\*/', code, re.DOTALL)

# 提取 HTML 块内容(跨行)
re.findall(r'<div>.*?</div>', html, re.DOTALL)

详细模式(x / re.VERBOSE)

复杂的正则表达式可以通过详细模式加注释,大幅提升可读性:

email_pattern = re.compile(r"""
    (?P<local>       # 本地部分
        [a-zA-Z0-9._%+-]+   # 用户名
    )
    @                        # @ 符号
    (?P<domain>              # 域名部分
        [a-zA-Z0-9.-]+       # 域名
        \.[a-zA-Z]{2,}       # 顶级域名
    )
""", re.VERBOSE | re.IGNORECASE)

m = email_pattern.match('user@example.com')
print(m.group('local'))   # 'user'
print(m.group('domain'))  # 'example.com'
TIP详细模式下,空格和 # 注释会被忽略。如果模式中需要匹配字面空格,要用 \ (反斜杠空格)或 \s 代替。

组合多个标志

# Python 用 | 组合
re.compile(r'pattern', re.IGNORECASE | re.MULTILINE | re.DOTALL)

# 或简写
re.compile(r'pattern', re.I | re.M | re.S)

// JavaScript:在结尾叠加标志字母
/pattern/gims

内联标志(Inline Flags)

可以在正则内部嵌入标志,影响部分模式(PCRE/Python 支持):

(?i)hello         # 整个模式忽略大小写
(?i:hello)        # 只在这个分组内忽略大小写
(?i)hello(?-i)world  # hello 不区分大小写,world 区分

JavaScript 的 y(粘滞)标志

const re = /\d+/y
re.lastIndex = 3
'abc123'.match(re)  // → ['123'](从位置 3 开始精确匹配)

小结