kLibRegexDsl Help

KLibRegexDsl

Maven Central Maven Snapshots

A tiny Regex DSL library for Kotlin Multiplatform.

Why

Regular expressions are a powerful tool, but a bit of a nightmare to read and maintain. In fact, they aren't ideal to write either: the syntax is not always intuitive or simple to remember, and it's quite easy to make mistakes - which will typically be detected at run-time only.

Using a DSL instead fixes these issues (albeit at the cost of verbosity - but as Kotlin developers, we like verbose, don't we?)

As an illustration, compare these two ways to express "Time Format HH:MM 12-hour, optional leading 0":

(0?[1-9]|1[0-2]]):[0-5][0-9]

vs

val hours = Group( Either( Sequence( Characters("0").onceOrNotAtAll(), characterClass('1'..'9'), ), Sequence( Characters("1"), characterClass('0'..'2'), ) ) ) val separator = Characters(":") val minutes = Sequence( characterClass('0'..'5'), characterClass('0'..'9'), ) val timeRegex = Sequence( hours, separator, minutes )

Which one is easier to read?

Fooled you - the first one isn't even valid (duplicated bracket)! You may have missed it, but I don't blame you: it is easy to miss.

As a bonus, an explicit API can abstract platform-specific differences (did you know . doesn't have the exact same meaning on JVM, JS and native? See 'Portability' section below).

If that convinced you, continue reading.

Usage

1/ Add the dependencies to your project

dependencies { /* ... */ implementation("org.jraf.klibregexdsl:klibregexdsl:1.1.0") }

(The artifact is hosted on Maven Central)

2/ Use it

The API is pretty self-explanatory so here's an example:

// Note: this is of course a very naive implementation of an email regex val localPart = union( characterClass('a'..'z'), characterClass('A'..'Z'), characterClass('0'..'9'), characterClass('.', '+', '-'), ).repeated(1..255) val at = Characters("@") val domain = union( AsciiAlphanumeric, characterClass('.', '-'), ).oneOrMoreTimes() val tld = Group( Either( Characters(".com"), Characters(".net"), Characters(".edu"), Characters(".org"), ) ) val emailRegexNode = Sequence( localPart, at, domain, tld ) // emailRegexNode.toString(): // - JVM: [a-zA-Z0-9.+\-]{1,255}@[a-zA-Z0-9.\-]+(\Q.com\E|\Q.net\E|\Q.edu\E|\Q.org\E) // - JS: [a-zA-Z0-9.+\-]{1,255}@[a-zA-Z0-9.\-]+(\.com|\.net|\.edu|\.org) val emailRegex: Regex = emailRegexNode.toRegex()

You can also have a look at the sample.

Portability

KLibRegexDsl targets the JVM, JavaScript, and Kotlin/Native on Apple platforms (macOS arm64, iOS arm64, and iOS simulator arm64).

The API in org.jraf.klibregexdsl is safe to use from commonMain: its predefined character classes and operators have the same matching behavior on every supported target. This includes ASCII classes such as AsciiAlphanumeric, Unicode general categories such as UnicodeLetter, and portable WhitespaceCharacter, AnyCharacter, and word-boundary matchers.

toString() returns a diagnostic representation that can differ by target - use toRegex() to obtain a regex that adheres to the portability contract.

Engine-specific features are kept out of common code. JVM-only classes and anchors live in org.jraf.klibregexdsl.jvm:

import org.jraf.klibregexdsl.jvm.BeginningOfInput import org.jraf.klibregexdsl.jvm.JavaWhitespace val inputOnly = Sequence(BeginningOfInput, Characters("hello"))

JVM code can also use QuantifierType.POSSESSIVE; common, JavaScript, and Native code only expose GREEDY and RELUCTANT.

Raw deliberately bypasses these guarantees. Use it only when the caller owns the target regex syntax.

License

Copyright (C) 2020-present Benoit 'BoD' Lubek (BoD@JRAF.org) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Last modified: 11 July 2026