#regex #pattern-matching #bot #dsl #discord


A domain specific pattern matching language made for defining bot commands

18 releases (8 breaking)

Uses new Rust 2021

new 0.9.0 May 16, 2022
0.7.3 May 6, 2022
0.7.0 Feb 17, 2022
0.6.2 Nov 22, 2021

#142 in Parser implementations

Download history 8/week @ 2022-01-28 3/week @ 2022-02-04 11/week @ 2022-02-11 25/week @ 2022-02-18 1/week @ 2022-02-25 2/week @ 2022-03-04 40/week @ 2022-03-11 53/week @ 2022-03-18 1/week @ 2022-04-01 13/week @ 2022-04-08 13/week @ 2022-04-22 90/week @ 2022-04-29 149/week @ 2022-05-06 324/week @ 2022-05-13

580 downloads per month




A domain specific pattern matching language made mainly for defining bot commands.

Crate Examples

Please check out the examples subdirectory of this repository.


  • While declaring commands, any kind of whitespace (space, tab, newline, crlf) are treated the same.
  • <> defines a capture.
  • [] defines a list of captures to be matched out of order.
  • You can include a space literal by escaping it with \\. I.e. .foo\ bar will match the literal "foo bar" but not "foo bar".

Capture Syntax

You can define captures in 3 ways:



  • ?: Match this capture 1 or 0 times.
  • *: Match this capture 0 or more times. The captures will be returned in a Vec.
  • +: Match this capture at least once. The values are returned in a Vec.
  • None: Match this exactly once.

If you use the first form, the default is to match on words (whitespace separated). Otherwise you must use a filter.

Filter Syntax

Filters are exactly like a function call in any mainstream language. They may take arguments. Arguments are always quoted strings.

Some examples:

  • starts("--")
  • foo()


Strings are always quoted with one of the ", ' or ```.

You can escape the quotation to include it in the string.

Some more escape patterns are recognized:

  • \n: newline.
  • \t: tab.
  • \r: carriage return.

Capture Group Syntax

A capture group defines a list of patterns that will be matched out of order. There are two forms of capture groups:

  • Priority groups: These are delimited with [] and the match priority of the captures enclosed are unchanged.
  • Normal group: These groups are enclosed in {} and the enclosed captures may be re-ordered for potentially more matches.

The syntax is as follows:

Priority groups:


Normal groups:



[<first> <second> <maybe_third?>]

Some defaults

  • Patterns have an implicit starting anchor (^ in regex).
  • Whitespace is only used as a terminator while matching.
  • starts and ends filters trim the match.


Run code

This example demonstrates a command for running code. The flags are optional but must start with -- The code block is not optional and must either start and end with:

  • "```"
  • "`" Or,
  • Starts with ```rust or ```rs and ends with ```.
<flags*: starts("--")>
	starts("```rust", "```rs", "```"), ends("```");
	starts("`"), ends("`");

Get a Bible Verse

This example command has 3 arguments:

  • book: required, must start with "book=
  • chapter: Optional, must start with either chapter= or ch=, case is not important.
  • verse: optional, must start with verse=.

Since the patterns are wrapped in [], they can be matched out of order.

	<book: starts("book=")>
	<chapter?: starts("chapter=", "ch="), nocase()>
	<verse?: starts("verse=")>

Bet some credits

This basic example command lets you bet some of your discord credits. The only required argument is the amount.

.bet <amount>

See a tag

This command takes 1 or more space separated arguments. It does not specify any pattern so the defaults apply:

  • Arguments are whitespace separated.
.tag <tags+:>


Every filter can be used any number of times, the arguments are combined into one filter.

  • starts(prefix1, prefix2, ...prefixN): Any of the given prefixes must match.
  • ends(suffix1, suffix2, ...suffixN): Any of the suffixes must match.
  • eq(s1, s2, ...sN): Must match any string given as an argument. Only other filter that can occur if eq is specified is nocase. "foo" is shorthand for eq("foo").
  • nocase(): Ignore case while matching. Not always accurate and ignored while matching suffixes.
  • notrim(): Do not trim the prefix/suffix while using starts() or ends(). Only valid in those two filters.


~55K SLoC