FlowLibs
Browse Cloud FlowsConnectorsAI ToolsDev ToolsPricingAboutContact
Dev Tools/Regex

Regex Reference

Regular expressions in Power Fx — the IsMatch, Match, and MatchAll functions behind validation and text extraction in canvas apps, model-driven apps, Copilot Studio, and Power Pages. Match options, the Match enum, a full syntax cheat sheet, the cross-platform subset Power Fx actually allows, plus copy-paste validation and parsing recipes.

Reference24 min read·Updated 2026-06-16
RegexRegular ExpressionsIsMatchMatchMatchAllValidationPower FxPower AppsCopilot StudioPatterns

On this page

  • Where regex lives in Power Platform
  • IsMatch, Match & MatchAll
  • What Match and MatchAll return
  • Match options
  • Predefined Match enum patterns
  • Characters & escapes
  • Character classes
  • Anchors & assertions
  • Quantifiers
  • Groups, alternation & submatches
  • Power Fx regex constraints
  • Validation recipes
  • Extraction & parsing recipes
  • Using regex in a Power App
  • Common gotchas

Where regex lives in Power Platform

Regex in the Power Platform is a Power Fx feature. Three functions take a pattern — IsMatch (validate), Match (extract the first hit), and MatchAll (extract every hit). They run anywhere Power Fx runs: canvas apps, model-driven custom pages, Copilot Studio, Power Pages, Dataverse low-code (formula columns and low-code plug-ins), and the Power Platform CLI. The full reference is IsMatch, Match, and MatchAll.

Cloud flows have no regex

Workflow Definition Language (the cloud-flow expression language) has no regular-expression function. Use indexOf / split / slice, or offload to Office Scripts / an Azure Function — see the Expressions guide. Everything on this page is Power Fx only.

The pattern must be a constant

The pattern *and* the options must be authoring-time constants — no variables, data sources, or other run-time values. You can still build a constant with &, string interpolation, Concatenate, Char, or UniChar over literal arguments. This is why an unsupported construct surfaces as a design-time error, not a run-time failure.

Power Fx runs on both JavaScript and .NET, so its regex dialect is a deliberately limited subset chosen to behave identically on every host. Patterns that work in other engines may be blocked or need a tweak — the Power Fx regex constraints section lists the differences. Full detail: Regular expressions in Power Fx.

IsMatch, Match & MatchAll

3/3
FunctionReturnsDefault scope
IsMatch( Text, Pattern [, Options] )true / false — does the text match the pattern?Complete in Power Apps (whole string); Contains elsewhere
Match( Text, Pattern [, Options] )A record for the first match, or blank if noneContains — match anywhere in the text
MatchAll( Text, Pattern [, Options] )A table with one record per match, or an empty tableContains — like the global "g" flag
powerfx
IsMatch( txtEmail.Text, Match.Email )            // true / false
Match( "Order 1042 shipped", "\d+" ).FullMatch   // "1042"
MatchAll( "a1 b2 c3", "\d" )                      // 3-row table: 1, 2, 3
Validate, extract one, extract all.

Just splitting? Use Split

If you only reach for MatchAll to break a string apart, the Split function is simpler and faster. Keep MatchAll for when you need the matched value, its position, or named submatches.

What Match and MatchAll return

Match returns a single record; MatchAll returns a table of those records. Each record carries the full match, its position, and any submatches you captured.

4/4
ColumnTypeNotes
FullMatchTextThe entire substring that matched the pattern.
StartMatchNumber1-based start position of the match (first character is 1).
<named submatch>TextOne column per (?<name>…) group — read it as .name.
SubMatchesTableSingle-column (Value) table of numbered groups — only when MatchOptions.NumberedSubMatches is set.
powerfx
With(
    { m: Match( "SKU-7781", "SKU-(?<id>\d+)" ) },
    m.FullMatch    // "SKU-7781"
    // m.StartMatch  -> 1
    // m.id          -> "7781"
)
Read FullMatch, position, and a named submatch.

Test for no match

Match returns blank when nothing matches — test it with IsBlank(). MatchAll returns an empty table — test it with IsEmpty(). Reading .FullMatch off a blank Match result is itself blank, not an error.

Match options

Pass one or more MatchOptions as the third argument, combined with &. Each has an inline equivalent you can place at the very start of the pattern instead (for example (?i) for IgnoreCase).

9/9
MatchOptionEffectEquivalent / note
MatchOptions.CompleteWhole string must match, start to end.Adds ^…$. Default for IsMatch in Power Apps.
MatchOptions.ContainsPattern may appear anywhere in the text.Default for Match / MatchAll (and IsMatch outside Power Apps).
MatchOptions.BeginsWithPattern must match from the start.Adds ^ to the front.
MatchOptions.EndsWithPattern must match the end.Adds $ to the end.
MatchOptions.IgnoreCaseCase-insensitive (culture-invariant)."i" modifier / (?i).
MatchOptions.Multiline^ and $ match at line breaks too."m" modifier / (?m).
MatchOptions.DotAll. also matches newline characters."s" modifier / (?s). Not in classic Power Apps.
MatchOptions.FreeSpacingIgnore whitespace + allow # comments in the pattern."x" modifier / (?x). Not in classic Power Apps.
MatchOptions.NumberedSubMatchesNumbered capture groups + \1 backrefs; disables named captures.Default in classic Power Apps.
powerfx
IsMatch( "HELLO world", "hello", MatchOptions.Contains & MatchOptions.IgnoreCase )   // true

// Inline form — same as above, options at the very start of the pattern:
IsMatch( "HELLO world", "(?i)hello", MatchOptions.Contains )                        // true
Combine options with &.

IgnoreCase is culture-invariant

Case-insensitive matching ignores culture (the industry norm, matching JavaScript and Perl). If you need a culture-aware match — e.g. Turkish I/i — spell it out with a character class like [Ii] instead of relying on IgnoreCase.

Predefined Match enum patterns

The Match enum gives readable names for common pieces. Concatenate them with & and mix in your own literals — "A" & Match.MultipleDigits matches an "A" followed by one or more digits. Reach for these before hand-writing the equivalent regex.

20/20
Match enumMatchesRegex
Match.AnyAny character.
Match.DigitA single digit\d
Match.MultipleDigitsOne or more digits\d+
Match.OptionalDigitsZero or more digits\d*
Match.LetterA single letter\p{L}
Match.MultipleLettersOne or more letters\p{L}+
Match.OptionalLettersZero or more letters\p{L}*
Match.SpaceA single whitespace character\s
Match.MultipleSpacesOne or more whitespace chars\s+
Match.OptionalSpacesZero or more whitespace chars\s*
Match.NonSpaceA single non-whitespace character\S
Match.MultipleNonSpacesOne or more non-whitespace chars\S+
Match.OptionalNonSpacesZero or more non-whitespace chars\S*
Match.EmailA basic email address (has @ and a dotted domain)see note
Match.CommaA comma,
Match.PeriodA period / dot\.
Match.HyphenA hyphen-
Match.TabA tab character\t
Match.LeftParenA left parenthesis\(
Match.RightParenA right parenthesis\)

Match.Email is a form check, not full validation

Match.Email is a quick test that input *looks* like local@host.tld. It deliberately doesn't enforce every RFC: it accepts some invalid forms (e.g. an underscore in the host) and rejects some valid ones (quoted addresses, IP-literal hosts). For a text-input check use it with MatchOptions.Complete. Run Text( Match.Email ) to see the exact regex your host uses.

Characters & escapes

9/9
TokenMatches
abcThe literal characters a, b, c, in order.
\. \? \* \+ \( \) \[ \] \^ \$ \| \\ \{ \}An escaped metacharacter, taken literally.
\tTab — same as Char(9).
\rCarriage return — Char(13).
\nNewline — Char(10).
\fForm feed — Char(12).
\x20Hex character code, exactly two hex digits.
\u2028Unicode code unit, exactly four hex digits.
\u{1F47B}Unicode code point, up to eight hex digits (0–10FFFF).

Reserved characters

These are special and must be escaped with a backslash to match literally: . ? * + ( ) [ ] ^ $ | \ { }. Octal escapes (\044) and \v are not supported — they're ambiguous across engines; use \x0b for a vertical tab and \x / \u for character codes.

Character classes

8/8
TokenMatches
.Any character except \r and \n (unless MatchOptions.DotAll).
[abc]Any one of a, b, or c.
[a-z0-9]Any character in the given ranges.
[^a-z]Any character NOT in the set (negated class).
\d \DA digit (0–9 and \p{Nd}) / a non-digit.
\w \WA word character ([\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}\p{Lm}]) / a non-word character.
\s \SA whitespace character / a non-whitespace character.
\p{L} \P{L}A Unicode category (here: any letter) / anything not in it.

Bracket rules are stricter than other engines

Inside [...]: escape a literal hyphen ([\-a], not [-a]), escape a leading bracket ([\[a]), and escape curly braces ([\{\}]). Empty [] isn't allowed, and classes can't be nested, subtracted, or intersected. The negated shorthands \D \W \S \P{} cannot appear inside a negated class [^…].

Unicode categories available to \p{} / \P{} include letters (L, Lu, Ll, Lt, Lm, Lo), marks (M, Mn, Mc, Me), numbers (N, Nd, Nl, No), punctuation (P, Pc, Pd, Ps, Pe, Pi, Pf, Po), symbols (S, Sm, Sc, Sk, So), separators (Z, Zs, Zl, Zp), and control/format (Cc, Cf).

Anchors & assertions

Assertions match a *position*, not characters — they don't consume any input.

7/7
TokenAsserts
^Start of the text (or of a line with MatchOptions.Multiline).
$End of the text (or of a line with MatchOptions.Multiline).
\b \BA word boundary / a non-boundary (Unicode letter definition).
(?=abc)Positive lookahead — what follows matches abc.
(?!abc)Negative lookahead — what follows does NOT match abc.
(?<=abc)Positive lookbehind — what precedes matches abc.
(?<!abc)Negative lookbehind — what precedes does NOT match abc.

Look-around is limited

A lookahead or lookbehind can't contain a submatch or an unlimited quantifier (*, +, {n,}), and can't be quantified from the outside. This is why the classic (?=.*\d) password idiom can fail on the Power Fx 1.0 engine — see the strong-password recipe for a portable alternative.

Quantifiers

8/8
TokenRepeatsGreed
?Zero or oneGreedy
*Zero or moreGreedy
+One or moreGreedy
{n}Exactly n—
{n,}At least nGreedy
{n,m}Between n and mGreedy
?? *? +?Lazy zero/one, zero/more, one/moreLazy (smallest match)
{n,}? {n,m}?Lazy at-least-n / between n and mLazy (smallest match)

Greedy vs lazy

Greedy quantifiers grab as much as possible then back off; add ? to make them lazy and grab as little as possible. On <a><b>, <.+> matches the whole string, while <.+?> matches just <a>. Possessive quantifiers (a++) and atomic groups are not supported.

Groups, alternation & submatches

7/7
TokenMeaning
(abc)Group elements so a quantifier applies — (abc)+ matches abcabc.
a|bAlternation — matches a or b (often inside a group).
(?:abc)Non-capturing group (this is the default behaviour anyway).
(?<name>abc)Named submatch — read it back as the column .name.
\k<name>Backreference to a named submatch.
(abc) … \1Numbered capture + backreference — only with MatchOptions.NumberedSubMatches.
(?# comment)Inline comment, ignored by the engine.

By default in the current Power Fx engine, plain (...) groups are non-capturing ("explicit capture") — capture only what you need with a named submatch (?<name>...), and reference it with \k<name>. Classic Power Apps defaults to MatchOptions.NumberedSubMatches, where (...) captures and you use \1-style backreferences. Named and numbered captures can't be mixed in one pattern.

powerfx
With(
    { d: Match( "2026-06-16", "(?<y>\d{4})-(?<m>\d{2})-(?<day>\d{2})" ) },
    // d.y = "2026", d.m = "06", d.day = "16"
    DateValue( d.y & "-" & d.m & "-" & d.day )
)
Named submatches read straight off the result record.

Power Fx regex constraints

Because one pattern is compiled to both JavaScript and .NET, Power Fx restricts regex to a curated subset that behaves the same on every host. Anything outside it errors at authoring time — which is also why the pattern has to be a constant. Keep these in mind:

  • Constant only — the pattern and options can't come from a variable, data source, or user input; build them from literals with & / Concatenate / Char / UniChar.
  • Named vs numbered captures can't mix — named is the default in the current engine (plain groups don't capture); numbered is the default in classic Power Apps. Pick one.
  • Negated shorthands \D \W \S \P{} can't be used inside a negated class [^…].
  • A possibly-empty submatch can't be quantified — (?<x>a*)+ errors, but (?<x>a+)+ is fine. The same applies to optional or alternated submatches that could match nothing.
  • No possessive quantifiers or atomic groups, no self-referencing captures ((a\1)), no two groups sharing a name, and no backreference into a look-around or a possibly-empty submatch.
  • Surrogate pairs (U+10000 and above) aren't supported inside character classes, and \p{} category data is only guaranteed for the Basic Multilingual Plane.
  • `\v` and octal escapes are disallowed — use \x0b and \x / \u codes.

Classic Power Apps vs Power Fx 1.0

Classic Power Apps uses an earlier regex engine: MatchOptions.DotAll and FreeSpacing aren't available, NumberedSubMatches is the default, surrogate pairs aren't treated as one character, and Match.Email / Match.Hyphen are defined differently. The newer engine described here arrives under a "Power Fx 1.0 compatibility" switch — test on the engine your app actually uses.

There is no regex replace

Power Fx has no regex-based replace. Substitute() replaces literal text only. To transform with a pattern, Match / MatchAll the pieces and rebuild the string, or offload the substitution to Office Scripts, a custom connector, or an Azure Function.

Validation recipes

IsMatch defaults to Complete in Power Apps, so each pattern below validates the whole input — pair it with a text input control. Every pattern is a constant. Patterns are shown as you'd type them in the formula bar.

13/13
ValidatesPatternNotes
EmailMatch.EmailPrefer the built-in enum; quick form check.
Email (explicit)^[\w.%+\-]+@[\w.\-]+\.[A-Za-z]{2,}$Hyphen escaped inside the class, per Power Fx rules.
US phone^\(?\d{3}\)?[\-. ]?\d{3}[\-. ]?\d{4}$Allows (123) 456-7890, 123.456.7890, 1234567890.
US ZIP^\d{5}(-\d{4})?$Five digits, optional +4.
US SSN^\d{3}-\d{2}-\d{4}$3-2-4 digits.
GUID^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$Standard 8-4-4-4-12 hex form.
IPv4^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$Each octet 0–255.
URL (http/https)^https?://\S+$Loose check — protocol + non-space rest.
Hex colour^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$#abc or #aabbcc.
Currency^\d+(\.\d{2})?$Digits, optional two decimals.
Time (24h)^([01]\d|2[0-3]):[0-5]\d$00:00–23:59.
ISO 8601 date^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$YYYY-MM-DD (range not month-aware).
Username^\w{3,16}$3–16 word characters (letters, digits, _).
powerfx
And(
    Len( txtPwd.Text ) >= 8,
    IsMatch( txtPwd.Text, "\d", MatchOptions.Contains ),       // a digit
    IsMatch( txtPwd.Text, "[a-z]", MatchOptions.Contains ),     // a lower-case letter
    IsMatch( txtPwd.Text, "[A-Z]", MatchOptions.Contains ),     // an upper-case letter
    IsMatch( txtPwd.Text, "[^\w\s]", MatchOptions.Contains )    // a symbol (not word / space)
)
Strong password — recommended portable form (no look-around).
powerfx
IsMatch(
    txtPwd.Text,
    "(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^\w\s]).{8,}",
    MatchOptions.Complete
)
Single-pattern alternative — works on the classic engine; the .* look-aheads are unsupported on Power Fx 1.0.

Extraction & parsing recipes

Match and MatchAll default to Contains, so they find a pattern anywhere. Capture the parts you want with named submatches and read them by column name.

powerfx
Match( "Invoice 4471 — due", "\d+" ).FullMatch    // "4471"
First number in a string.
powerfx
// MatchAll returns a table of records:
MatchAll( "loving #powerfx and #lowcode", "#\w+" )

// Flatten to "#powerfx, #lowcode":
Concat( MatchAll( txtPost.Text, "#\w+" ), FullMatch, ", " )
All hashtags as a table, then a delimited string.
powerfx
MatchAll(
    "env=prod;region=eus;tier=1",
    "(?<key>\w+)=(?<val>[^;]+)"
)
// each row: { key: "env", val: "prod", FullMatch: "env=prod", StartMatch: 1 }
Parse key=value pairs into named columns.
powerfx
With(
    { m: Match( "555-1234", "(\d{3})-(\d{4})", MatchOptions.NumberedSubMatches ) },
    Index( m.SubMatches, 1 ).Value & " / " & Index( m.SubMatches, 2 ).Value
)   // "555 / 1234"
Numbered submatches (classic engine) via the SubMatches table.

StartMatch pairs with Mid

StartMatch is 1-based, so it drops straight into Mid( text, Match(...).StartMatch, ... ) when you need the text around a hit rather than the hit itself.

Using regex in a Power App

Inline field validation message

powerfx
If(
    IsBlank( txtEmail.Text ) || IsMatch( txtEmail.Text, Match.Email ),
    "",
    "Enter a valid email address"
)
A label/error Text under the input — blank while valid.

Enable Submit only when the form is valid

powerfx
And(
    !IsBlank( txtName.Text ),
    IsMatch( txtEmail.Text, Match.Email ),
    IsMatch( txtPhone.Text, "^\d{3}-\d{3}-\d{4}$" )
)
Button DisplayMode: If(<this>, DisplayMode.Edit, DisplayMode.Disabled).

Colour the border by validity

powerfx
// Text input BorderColor
If( IsMatch( Self.Text, "^\d{5}$" ), Color.Green, Color.Red )

You can't build the pattern at run time

Because the pattern must be a constant, you can't assemble a regex from a variable or from user input. For *dynamic* search-as-you-type, use Find, StartsWith, in, or Search instead — regex is for fixed, known patterns.

Power Pages: validate on the server too

The same functions work in model-driven apps and Power Pages, but client-side Power Fx on a public Power Pages site can be bypassed. Treat IsMatch as a UX nicety and re-validate on the server (Dataverse plug-in or a flow) before trusting the input.

Common gotchas

  • Default scope differs — IsMatch is Complete (whole string) in Power Apps; Match / MatchAll are Contains. Add ^…$ or the explicit option when it matters.
  • Pattern must be a constant — no variables or data sources; that's why unsupported syntax errors at authoring time, not run time.
  • Named vs numbered captures can't mix — current engine captures only named groups by default; classic Power Apps numbers all groups (\1). Don't combine the two.
  • `\D \W \S \P{}` can't go inside `[^…]` — and literal hyphens, leading brackets, and braces must be escaped inside a class.
  • `.` skips newlines unless MatchOptions.DotAll — and DotAll / FreeSpacing aren't available in classic Power Apps.
  • Look-around can't hold an unlimited quantifier or be quantified — the (?=.*\d) idiom may fail; prefer And() of several IsMatch(…, Contains) checks.
  • No regex replace — Substitute() is literal only; rebuild via Match / MatchAll or offload.
  • `Match.Email` is a form check, not full RFC validation — and IgnoreCase is culture-invariant.
  • Just splitting? Use `Split` — it's simpler and faster than MatchAll.
← All Dev ToolsUse these in your AI assistant →
Spotted an error or have a suggestion? Let us know
FlowLibs

A curated library of production-grade Power Automate cloud flow patterns. Packaged as managed solutions, ready to import into your environment.

Library

  • Browse Cloud Flows
  • Approvals
  • Email & Notifications
  • Reporting
  • Security & Compliance

AI

  • AI Tools
  • MCP Server
  • Generate a Token

Resources

  • About
  • FAQ
  • Support
  • Status
  • Contact
  • Power Automate Docs
  • Connector Reference

© 2026 FlowLibs. All rights reserved.

  • Privacy
  • Terms
  • Refunds
  • Cookies
  • Acceptable Use
  • DMCA
Help