jvolkman/re.bzl

A pure-Starlark regex library

9

stars

134

commits

Starlark

primary language

May 19, 2026

updated

Browse cluster: Regular expression engines and parsing

README

re.bzl

A pure Starlark implementation of a Regex engine. Vibe coded with Gemini.

Overview

re.bzl provides a Thompson NFA-based regex engine designed for Bazel. It provides a significant subset of RE2 syntax with linear-time performance guarantees.

Usage

For full API documentation, see the API Reference.

load("@re.bzl", "re")

# Search for a pattern
m = re.search(r"(\w+)=(\d+)", "key=123")
if m:
    print(m.group(1)) # "key"
    print(m.group(2)) # "123"

# Replacement
result = re.sub(r"a+", "b", "abaac") # "bbbc"

# Find All
tokens = re.findall(r"\w+", "hello world") # ["hello", "world"]

# Full Match
is_exact = re.fullmatch(r"v\d+\.\d+", "v1.2") # <MatchObject> or None

# Pre-compile for reuse (more efficient for multiple searches)
prog = re.compile(r"\d+")
if prog.search("123"):
    print("Found digits")

Performance and Feasibility

This was mostly done as a fun project. Starlark (or any build configuration language) is not an optimal tool for building a regex engine.

That said, it does work, and by optimizing for performance within the constraints of Starlark (offloading as much work as possible to Java-backed string methods), it has shown to be as fast as custom parsing logic in when used on real-world input in toml.bzl while offering concise way to describe token matching expressions.

Syntax Reference

re.bzl aims to support most of RE2 syntax. Below is a detailed reference of supported features.

Single-character expressions

SyntaxDescription
.any character, possibly including newline (s=true)
[xyz]character class
[^xyz]negated character class
\dPerl character class (digits)
\Dnegated Perl character class
[[:alpha:]]ASCII character class
[[:^alpha:]]negated ASCII character class

Composites

SyntaxDescription
xyx followed by y
x|yx or y (prefer x)

Repetitions

SyntaxDescription
x*zero or more x, prefer more
x+one or more x, prefer more
x?zero or one x, prefer one
x{n,m}n or n+1 or ... or m x, prefer more
x{n,}n or more x, prefer more
x{n}exactly n x
x*?zero or more x, prefer fewer
x+?one or more x, prefer fewer
x??zero or one x, prefer zero
x{n,m}?n or ... or m x, prefer fewer
x{n,}?n or more x, prefer fewer
x{n}?exactly n x

Grouping

SyntaxDescription
(re)numbered capturing group (submatch)
(?P<name>re)named & numbered capturing group (submatch)
(?<name>re)named & numbered capturing group (submatch)
(?:re)non-capturing group
(?flags)set flags within current group; non-capturing
(?flags:re)set flags during re; non-capturing

Flags

FlagAPI Constant(s)Description
ire.I, re.IGNORECASEcase-insensitive (default false)
mre.M, re.MULTILINEmulti-line mode: ^ and $ match begin/end line (default false)
sre.S, re.DOTALLlet . match \n (default false)
xre.X, re.VERBOSEverbose: ignore whitespace and allow comments (default false)
Ure.U, re.UNGREEDYungreedy: swap meaning of x* and x*?, etc (default false)

Empty strings (Anchors)

SyntaxDescription
^at beginning of text or line (m=true)
$at end of text or line (m=true)
\Aat beginning of text
\zat end of text
\bat ASCII word boundary
\Bnot at ASCII word boundary

Escape sequences

SyntaxDescription
\abell (≡ \007)
\fform feed (≡ \014)
\thorizontal tab (≡ \011)
\nnewline (≡ \012)
\rcarriage return (≡ \015)
\vvertical tab character (≡ \013)
\123octal character code (up to three digits)
\x7Fhex character code (exactly two digits)
\x{7F}hex character code
\Q...\Eliteral text ... even if ... has punctuation

ASCII Character Classes

SyntaxDescription
[[:alnum:]]alphanumeric (≡ [0-9A-Za-z])
[[:alpha:]]alphabetic (≡ [A-Za-z])
[[:ascii:]]ASCII (≡ [\x00-\x7F])
[[:blank:]]blank (≡ [\t ])
[[:cntrl:]]control (≡ [\x00-\x1F\x7F])
[[:digit:]]digits (≡ [0-9])
[[:graph:]]graphical (≡ [!-~])
[[:lower:]]lower case (≡ [a-z])
[[:print:]]printable (≡ [ -~])
[[:punct:]]punctuation (≡ [!-/:-@[- + "" + {-~]`)
[[:space:]]whitespace (≡ [\t\n\v\f\r ])
[[:upper:]]upper case (≡ [A-Z])
[[:word:]]word characters (≡ [0-9A-Za-z_])
[[:xdigit:]]hex digit (≡ [0-9A-Fa-f])

Compatibility

re.bzl aims for high compatibility with RE2 syntax. Most non-Unicode features are supported.

Like RE2, re.bzl does not support backreferences and lookarounds.

Unicode Support

Starlark strings are sequences of environment-dependent elements (UTF-K).

  • In Bazel (Java): Strings are UTF-16. . matches one UTF-16 code unit. Non-BMP characters (like 🚀) are 2 units (surrogate pair). len('🚀') == 2.
  • In starlark-go: Strings are UTF-8. . matches one byte. 🚀 is 4 bytes. len('🚀') == 4.
  • Character classes [...] and [^...] operate on these individual elements.
  • Quantifiers apply to the preceding atom. For multibyte/multi-unit characters, you must group them (e.g., (🚀)+) to match the full sequence.
  • Unicode character categories (\p{...}) are not supported.

Installation

Add the following to your MODULE.bazel:

bazel_dep(name = "re.bzl", version = "0.1.0")

License

Apache 2.0

Contributors

jvolkman

133 commits

darkrift

1 commits

jvolkman/re.bzl

A pure-Starlark regex library

9

stars

134

commits

Starlark

primary language

May 19, 2026

updated

Browse cluster: Regular expression engines and parsing

README

re.bzl

A pure Starlark implementation of a Regex engine. Vibe coded with Gemini.

Overview

re.bzl provides a Thompson NFA-based regex engine designed for Bazel. It provides a significant subset of RE2 syntax with linear-time performance guarantees.

Usage

For full API documentation, see the API Reference.

load("@re.bzl", "re")

# Search for a pattern
m = re.search(r"(\w+)=(\d+)", "key=123")
if m:
    print(m.group(1)) # "key"
    print(m.group(2)) # "123"

# Replacement
result = re.sub(r"a+", "b", "abaac") # "bbbc"

# Find All
tokens = re.findall(r"\w+", "hello world") # ["hello", "world"]

# Full Match
is_exact = re.fullmatch(r"v\d+\.\d+", "v1.2") # <MatchObject> or None

# Pre-compile for reuse (more efficient for multiple searches)
prog = re.compile(r"\d+")
if prog.search("123"):
    print("Found digits")

Performance and Feasibility

This was mostly done as a fun project. Starlark (or any build configuration language) is not an optimal tool for building a regex engine.

That said, it does work, and by optimizing for performance within the constraints of Starlark (offloading as much work as possible to Java-backed string methods), it has shown to be as fast as custom parsing logic in when used on real-world input in toml.bzl while offering concise way to describe token matching expressions.

Syntax Reference

re.bzl aims to support most of RE2 syntax. Below is a detailed reference of supported features.

Single-character expressions

SyntaxDescription
.any character, possibly including newline (s=true)
[xyz]character class
[^xyz]negated character class
\dPerl character class (digits)
\Dnegated Perl character class
[[:alpha:]]ASCII character class
[[:^alpha:]]negated ASCII character class

Composites

SyntaxDescription
xyx followed by y
x|yx or y (prefer x)

Repetitions

SyntaxDescription
x*zero or more x, prefer more
x+one or more x, prefer more
x?zero or one x, prefer one
x{n,m}n or n+1 or ... or m x, prefer more
x{n,}n or more x, prefer more
x{n}exactly n x
x*?zero or more x, prefer fewer
x+?one or more x, prefer fewer
x??zero or one x, prefer zero
x{n,m}?n or ... or m x, prefer fewer
x{n,}?n or more x, prefer fewer
x{n}?exactly n x

Grouping

SyntaxDescription
(re)numbered capturing group (submatch)
(?P<name>re)named & numbered capturing group (submatch)
(?<name>re)named & numbered capturing group (submatch)
(?:re)non-capturing group
(?flags)set flags within current group; non-capturing
(?flags:re)set flags during re; non-capturing

Flags

FlagAPI Constant(s)Description
ire.I, re.IGNORECASEcase-insensitive (default false)
mre.M, re.MULTILINEmulti-line mode: ^ and $ match begin/end line (default false)
sre.S, re.DOTALLlet . match \n (default false)
xre.X, re.VERBOSEverbose: ignore whitespace and allow comments (default false)
Ure.U, re.UNGREEDYungreedy: swap meaning of x* and x*?, etc (default false)

Empty strings (Anchors)

SyntaxDescription
^at beginning of text or line (m=true)
$at end of text or line (m=true)
\Aat beginning of text
\zat end of text
\bat ASCII word boundary
\Bnot at ASCII word boundary

Escape sequences

SyntaxDescription
\abell (≡ \007)
\fform feed (≡ \014)
\thorizontal tab (≡ \011)
\nnewline (≡ \012)
\rcarriage return (≡ \015)
\vvertical tab character (≡ \013)
\123octal character code (up to three digits)
\x7Fhex character code (exactly two digits)
\x{7F}hex character code
\Q...\Eliteral text ... even if ... has punctuation

ASCII Character Classes

SyntaxDescription
[[:alnum:]]alphanumeric (≡ [0-9A-Za-z])
[[:alpha:]]alphabetic (≡ [A-Za-z])
[[:ascii:]]ASCII (≡ [\x00-\x7F])
[[:blank:]]blank (≡ [\t ])
[[:cntrl:]]control (≡ [\x00-\x1F\x7F])
[[:digit:]]digits (≡ [0-9])
[[:graph:]]graphical (≡ [!-~])
[[:lower:]]lower case (≡ [a-z])
[[:print:]]printable (≡ [ -~])
[[:punct:]]punctuation (≡ [!-/:-@[- + "" + {-~]`)
[[:space:]]whitespace (≡ [\t\n\v\f\r ])
[[:upper:]]upper case (≡ [A-Z])
[[:word:]]word characters (≡ [0-9A-Za-z_])
[[:xdigit:]]hex digit (≡ [0-9A-Fa-f])

Compatibility

re.bzl aims for high compatibility with RE2 syntax. Most non-Unicode features are supported.

Like RE2, re.bzl does not support backreferences and lookarounds.

Unicode Support

Starlark strings are sequences of environment-dependent elements (UTF-K).

  • In Bazel (Java): Strings are UTF-16. . matches one UTF-16 code unit. Non-BMP characters (like 🚀) are 2 units (surrogate pair). len('🚀') == 2.
  • In starlark-go: Strings are UTF-8. . matches one byte. 🚀 is 4 bytes. len('🚀') == 4.
  • Character classes [...] and [^...] operate on these individual elements.
  • Quantifiers apply to the preceding atom. For multibyte/multi-unit characters, you must group them (e.g., (🚀)+) to match the full sequence.
  • Unicode character categories (\p{...}) are not supported.

Installation

Add the following to your MODULE.bazel:

bazel_dep(name = "re.bzl", version = "0.1.0")

License

Apache 2.0

Contributors

jvolkman

133 commits

darkrift

1 commits

Languages

Starlark

100.0%