protected function _compile_regex($route)
    {
        $pattern = '`(/|\.|)\[([^:\]]*+)(?::([^:\]]*+))?\](\?|)`';

        if ( preg_match_all($pattern, $route, $matches, PREG_SET_ORDER) ) {
            $match_types = array(
                'i'  => '[0-9]++',
                'a'  => '[0-9A-Za-z]++',
                'h'  => '[0-9A-Fa-f]++',
                '*'  => '.+?',
                ''   => '[^/]++'
            );
            foreach ( $matches as $match ) {
                list($block, $pre, $type, $param, $optional) = $match;

                if ( isset($match_types[$type]) ) {
                    $type = $match_types[$type];
                }
                if ( $param ) {
                    $param = "?<{$param}>";
                }
                if ( $optional ) {
                    $optional = '?';
                }

                $replaced = "(?:{$pre}({$param}{$type})){$optional}";
                $route = str_replace($block, $replaced, $route);
            }
        }
        if ( substr($route, strlen($route) - 1) != '/' ) {
            $route .= '/?';
        }
        return "`^{$route}$`";
    }