protected function compile()
    {
        // The URI should be considered literal except for keys and optional parts
        // Escape everything preg_quote would escape except for : ( ) < >
        $regex = preg_replace('#' . self::REGEX_ESCAPE . '#', '\\\\$0', $this->uri);

        if (strpos($regex, '(') !== false) {
            // Make optional parts of the URI non-capturing and optional
            $regex = str_replace(array('(', ')'), array('(?:', ')?'), $regex);
        }

        // Insert default regex for keys
        $regex = str_replace(array('<', '>'), array('(?P<', '>' . self::REGEX_SEGMENT . ')'), $regex);

        $search = $replace = array();
        foreach ($this->regex as $key => $value) {
            $search[] = "<$key>" . self::REGEX_SEGMENT;
            $replace[] = "<$key>$value";
        }

        // Replace the default regex with the user-specified regex
        return sprintf('#^%s$#', str_replace($search, $replace, $regex));
    }