Skip to content

UXCharClass

UXCharClass is what a regex bracket expression compiles to: the set of character codes it accepts, and whether the sense is inverted.

#use <UXKit> // or #import "UXRegex.xc"
class UXCharClass : Object {
UXIndexSet* set; // the codes named
bool negated; // [^...] inverts the answer
}
void addChar(i32 c)
void addRange(i32 lo, i32 hi) // inclusive at both ends
bool contains(i32 c)

UXRegex builds these while parsing. The matcher’s CLASS instruction is a single contains call.

[a-z] set = {a…z}, negated = false
[^a-z] set = {a…z}, negated = true

[^a-z] stores the same set and flips the answer. Storing the complement would mean enumerating every code that is not a lowercase letter, which is most of them, and would need an upper bound to stop at.

[^a] therefore means anything but a, with no ceiling, and the class costs the same whichever way round it is written.

UXIndexSet* set

Character codes are indices, so the set is a UXIndexSet, the same run-coalescing structure a table view uses for selected rows.

A range like a-z is stored as one run, not 26 entries, and [A-Za-z0-9_] is four runs however many characters it names. Membership is a search over runs rather than over characters.

addRange takes an inclusive lohi pair, as a regex writes it, and converts to the length-based form the index set wants. A reversed range (hi < lo) adds nothing.

\d, \w, \s and their negations are built as UXCharClass instances with the appropriate ranges added. There is no separate instruction for them and no fast path.

They match what their ranges say: \w is [A-Za-z0-9_], \s is the ASCII whitespace codes, \d is [0-9]. There are no Unicode categories and no locale effects.

The matcher works on bytes, so a class holds byte values. A UTF-8 character outside ASCII is several bytes, and [é] is a class of the two bytes that spell it. It matches either byte on its own.

ASCII classes, which regex patterns in this toolkit are for, are unaffected. Keep this in mind before writing a class that contains a non-ASCII literal.

addChar · addRange · contains

void addChar(i32 c)

Add one code.

void addRange(i32 lo, i32 hi)

Add an inclusive range. hi < lo is ignored.

bool contains(i32 c)

Membership, with negated applied. This is the only question the matcher asks.

UXIndexSet* set
bool negated