re.RegexFlag

Five flags cover almost everything: I ignores case, M makes ^ and $ work per line, S lets . match newlines, X allows whitespace and comments, A restricts \w \d \s to ASCII. Each has a one-letter alias and an inline form.

re constantsPython 3.6+ (RegexFlag)Live demo
Common call
re.findall(r'^\w+', text, flags=re.I | re.M)
Returns
re.IGNORECASE|re.MULTILINE — flags combine with |
Replaces
lowercasing the text first, splitting into lines first
Watch out
Pass flags by keyword to sub/split: the 4th positional argument of re.sub is count, not flags
re.IGNORECASE | re.MULTILINE | re.DOTALL | re.VERBOSE | re.ASCII | re.UNICODE | re.LOCALE | re.NOFLAG
→ re.RegexFlag

Demo

Live evaluation
Without and with re.IGNORECASE.
Try:
Inputs
patternstra regular expression
textstrtext
Code
import re
(re.findall('python', 'Python PYTHON python'), re.findall('python', 'Python PYTHON python', re.IGNORECASE))
Result
(['python'], ['Python', 'PYTHON', 'python'])

IGNORECASE uses Unicode case rules for str patterns, so straße matches STRAßE and ω matches Ω. MULTILINE only changes ^ and $; DOTALL only changes the dot — they are independent and are often used together. In VERBOSE mode a literal space must be escaped (\ ) or written as [ ] — and 'New\ York | Paris' shows alternation still works with the layout spaces removed.

Parameters

NameTypeRequiredDescription
re.I / re.IGNORECASERegexFlag = 2noCase-insensitive matching (Unicode case folding for str patterns). Inline: (?i).
re.M / re.MULTILINERegexFlag = 8no^ and $ also match at the start/end of every line. Inline: (?m).
re.S / re.DOTALLRegexFlag = 16no. also matches a newline. Inline: (?s).
re.X / re.VERBOSERegexFlag = 64noWhitespace in the pattern is ignored and # starts a comment (except inside [...] or when escaped). Inline: (?x).
re.A / re.ASCIIRegexFlag = 256no\w \W \b \B \d \D \s \S and case-insensitivity use ASCII only. Inline: (?a).
re.U / re.UNICODERegexFlag = 32noThe default for str patterns; kept for compatibility. Incompatible with re.ASCII.
re.L / re.LOCALERegexFlag = 4noLocale-dependent matching — bytes patterns only; a ValueError with str.
re.NOFLAGRegexFlag = 0noNo flags (3.11+) — a readable default for code that adds flags conditionally.

Return value

re.RegexFlag — An enum.IntFlag; combine members with | and pass them as flags= (or put (?imsxa) at the start of the pattern).

Common patterns

Combine flags
Flags are IntFlag members: | combines them.
import re
pat = re.compile(r'^error:.*$', re.IGNORECASE | re.MULTILINE)
A documented pattern with VERBOSE
Comments and line breaks make long patterns maintainable.
import re
DATE = re.compile(r'''
    (?P<year>\d{4})  -   # year
    (?P<month>\d{2}) -   # month
    (?P<day>\d{2})       # day
''', re.VERBOSE)
Inline flags and scoped flags
(?i) at the very start applies to the whole pattern; (?i:...) only to the group (3.6+).
import re
re.compile(r'(?i)^subject:')
re.compile(r'ID-(?i:[a-f0-9]+)')
Build flags conditionally
re.NOFLAG (3.11+) is a clear starting value.
import re
flags = re.NOFLAG
if ignore_case:
    flags |= re.IGNORECASE
pat = re.compile(needle, flags)

Examples

1. Case-insensitive
import re re.findall(r'python', 'Python PYTHON python', re.I)
Returns
['Python', 'PYTHON', 'python']
2. ^ on every line
import re re.findall(r'^\w+', 'one\ntwo\nthree', re.M)
Returns
['one', 'two', 'three']
3. . across a newline
import re re.search(r'a.b', 'a\nb', re.S)
Returns
<re.Match object; span=(0, 3), match='a\nb'>
4. ASCII-only \w
import re re.findall(r'\w+', 'café naïve', re.A)
Returns
['caf', 'na', 've']
5. Inline flag
import re re.findall(r'(?i)python', 'Python')
Returns
['Python']
6. Combined flags repr
import re re.I | re.M
Returns
re.IGNORECASE|re.MULTILINE
7. Flags are ints
import re (int(re.I), int(re.M), int(re.S), int(re.X), int(re.A))
Returns
(2, 8, 16, 64, 256)
8. Unicode digits by default
import re (re.findall(r'\d', '1٣'), re.findall(r'\d', '1٣', re.A))
Returns
(['1', '٣'], ['1'])

Pitfalls

1. Flags passed positionally to re.sub
re.sub's fourth parameter is count. re.I is 2, so this means "replace at most 2" — and nothing is case-insensitive.
re.sub(p, r, s, re.I)
import re
re.sub('a', '-', 'AaAa', re.I)
'A-A-'
flags=re.I
import re
re.sub('a', '-', 'AaAa', flags=re.I)
'----'
2. Inline global flags in the middle
Since 3.11 a global (?i) must be at the start. Use a scoped group (?i:...) elsewhere.
a(?i)b
import re
re.compile(r'a(?i)b')
re.PatternError: global flags not at the start of the expression at position 1
a(?i:b)
import re
re.findall(r'a(?i:b)', 'ab aB Ab')
['ab', 'aB']
3. Expecting MULTILINE to make . cross lines
MULTILINE is about ^ and $. The dot needs DOTALL.
re.M
import re
print(re.search(r'start.*end', 'start\nend', re.M))
None
re.S
import re
re.search(r'start.*end', 'start\nend', re.S)
<re.Match object; span=(0, 9), match='start\nend'>

When to use

Use it
  • IGNORECASE for user-facing search; MULTILINE for line-oriented text
  • DOTALL when a match may span lines; VERBOSE for any pattern longer than one line
  • ASCII when \w and \d must mean [a-zA-Z0-9_] and [0-9] (identifiers, protocols)
Reach for something else
  • LOCALE with str patterns — not allowed
  • UNICODE — it is already the default for str
  • IGNORECASE as a substitute for proper normalization (casefold, unicodedata)

Notes

CPython impl
re.RegexFlag is an enum.IntFlag defined in Lib/re/__init__.py; the bit values come from Lib/re/_constants.py (SRE_FLAG_*)
Inline
(?aiLmsux) at the start of the pattern sets flags for the whole pattern; (?imsx-imsx:...) sets or clears them inside a group (a, L, u can only be set, not cleared)
Versions
Flags became RegexFlag enum members in 3.6; NOFLAG was added in 3.11; since 3.11 global inline flags must be at the start
Pattern.flags
A compiled str pattern reports re.UNICODE (32) as well, even when you did not pass it
DEBUG
re.DEBUG (128) prints the parsed pattern while compiling — a debugging aid, not part of __all__

FAQ

Pass re.IGNORECASE (or re.I): re.search(r'python', text, re.I). Or start the pattern with (?i). For part of a pattern use a scoped group: (?i:python).