protected function compileRegex($rule)
    {
        $regex = '^' . preg_replace_callback(
            '@\{[\w]+\??\}@',
            function ($matches) {
                $optional = false;
                $key = str_replace(['{', '}'], '', $matches[0]);
                if (substr($key, -1) == '?') {
                    // Flag this token as optional.
                    $optional = true;
                }
                if (isset($this->customFilters[$key])) {
                    if (isset($this->defaultFilters[$this->customFilters[$key]])) {
                        return '(' . $this->defaultFilters[$this->customFilters[$key]] . ')' . (($optional) ? '?' : '');
                    } else {
                        if (
                            substr($this->customFilters[$key], 0, 1) == '{' &&
                            substr($this->customFilters[$key], -1) == '}'
                        ) {
                            throw new \RuntimeException(
                                "The custom filter named \"{$key}\" references a
                                non-existent builtin filter named \"{$this->customFilters[$key]}\"."
                            );
                        } else {
                            return '(' . $this->customFilters[$key] . ')' . (($optional) ? '?' : '');
                        }
                    }
                } elseif (isset($this->defaultTokens[$key])) {
                    return '(' . $this->defaultTokens[$key] . ')' . (($optional) ? '?' : '');
                } else {
                    return '(' . $this->defaultFilters['{default}'] . ')' . (($optional) ? '?' : '');
                }
            },
            $rule
        ) . '$';

        // Fix slash delimeters in regards to optional handling.
        $regex = str_replace(['?/', '??'], ['?/?', '?'], $regex);

        return $regex;
    }