Text Processingflags: g

Python f-String Expression

Match `{expression}` placeholders inside Python f-strings (or any single-brace template syntax), skipping `{{ }}` literal-brace escapes.

Try it in RegexPro →

Available in

JavaScript / ECMAScript code

jsJavaScript
const re = new RegExp("(?<!\\{)\\{([^{}]+)\\}(?!\\})", "g");
const input = "f\"Hello {name}, you are {age} years old\"";
const matches = [...input.matchAll(re)];
console.log(matches.map(m => m[0]));

Uses `String.prototype.matchAll` for global iteration (Node 12+ / all modern browsers).

Pattern

regexengine-agnostic
(?<!\{)\{([^{}]+)\}(?!\})   (flags: g)

Raw source: (?<!\{)\{([^{}]+)\}(?!\})

How it works

(?<!\{) is a negative lookbehind: the opening brace must not follow another `{`. \{ matches that brace, ([^{}]+) captures one or more non-brace characters as the expression, and \} matches the closing brace. (?!\}) is a negative lookahead: the closing brace must not be followed by another `}`. Together the lookarounds skip `{{ ... }}`, the f-string escape for literal braces — without them, \{([^{}]+)\} would still match the inner `{ ... }` of an escape. Limits: nested braces (e.g. a format spec like `{x:{width}}`) aren't handled, and a placeholder wrapped in escapes like `{{{x}}}` is skipped too. Go's RE2 has no lookarounds, so Go needs the workaround shown in its tab.

Examples

Input

f"Hello {name}, you are {age} years old"

Matches

  • {name}
  • {age}

Input

f"Total: {amount:.2f} USD"

Matches

  • {amount:.2f}

Input

f"escaped {{ not a placeholder }}"

No match

—

Input

f"{{literal}} but {value} is real"

Matches

  • {value}

Common use cases

  • •Static analysis of f-string usage
  • •Linting for unsafe expressions in templates
  • •Translating f-strings to .format() during downgrades
  • •Generating docs from template files

Related patterns