Parse an route pattern seeking for parameters and build the route regex.

@param string $pattern
@return array 0 => new route regex, 1 => map of parameter names
193512
protected function parsePlaceholders($pattern)
    {
        $params = [];
        $parser = $this->parser;

        preg_match_all("~" . $parser::DYNAMIC_REGEX . "~x", $pattern, $matches, PREG_SET_ORDER);

        foreach ((array) $matches as $key => $match) {
            $pattern = str_replace($match[0], isset($match[2]) ? "({$match[2]})" : "([^/]+)", $pattern);
            $params[$key] = $match[1];
        }

        return [$pattern, $params];
    }
841697
public function match($pattern, $to = null)
    {
        $route = clone $this->defaultRoute;
        $route->setPath($pattern);
        $this->controllers[] = $controller = new Controller($route);
        $route->setDefault('_controller', null === $to ? $this->defaultController : $to);

        return $controller;
    }
650489
public function parsePattern($pattern)
    {
        $withoutClosing = rtrim($pattern, "]");
        $closingNumber  = strlen($pattern) - strlen($withoutClosing);

        $segments = preg_split("~" . self::DYNAMIC_REGEX . "(*SKIP)(*F)|\[~x", $withoutClosing);
        $this->parseSegments($segments, $closingNumber, $withoutClosing);

        return $this->buildSegments($segments);
    }
1255882
protected function parsePattern($pattern)
    {
        $currentPos      = 0;
        $length          = strlen($pattern);
        $tokens          = [];
        $level           = 0;
        $quotedDelimiter = preg_quote($this->delimiter);

        while ($currentPos < $length) {
            preg_match('(\G(?P<literal>[^:{\[\]]*)(?P<token>[:\[\]]|$))', $pattern, $matches, 0, $currentPos);

            $currentPos += strlen($matches[0]);

            if (!empty($matches['literal'])) {
                $tokens[] = ['literal', $matches['literal']];
            }

            if ($matches['token'] === ':') {
                if (!preg_match(
                    '(\G(?P<name>[^:' . $quotedDelimiter . '{\[\]]+)(?:{(?P<delimiters>[^}]+)})?:?)',
                    $pattern,
                    $matches,
                    0,
                    $currentPos
                )) {
                    throw new Exception\RuntimeException('Found empty parameter name');
                }

                $tokens[] = [
                    'parameter',
                    $matches['name'],
                    isset($matches['delimiters']) ? $matches['delimiters'] : null
                ];

                $currentPos += strlen($matches[0]);
            } elseif ($matches['token'] === '[') {
                $tokens[] = ['optional-start'];
                $level++;
            } elseif ($matches['token'] === ']') {
                $tokens[] = ['optional-end'];
                $level--;

                if ($level < 0) {
                    throw new Exception\RuntimeException('Found closing bracket without matching opening bracket');
                }
            } else {
                break;
            }
        }

        if ($level > 0) {
            throw new Exception\RuntimeException('Found unbalanced brackets');
        }

        return $tokens;
    }
802991
protected function getSegments($pattern)
	{
		$segments = array();
		$parts = \explode("/", ltrim($pattern, "/"));

		foreach ($parts as $segment)
		{
			if (\strpos($segment, ":") !== false)
			{
				$segments[] = $this->parseSegment($segment);
			}
		}

		return $segments;
	}
975012
static protected function analysisPattern($pattern)
    {
        if (!($n = self::$_mbstringAvailable ? mb_strlen($pattern, APP_CHARSET) : strlen($pattern))) {
            return [];
        }
        $ps = [];
        $c0 = self::$_mbstringAvailable ? mb_substr($pattern, 0, 1, APP_CHARSET) : substr($pattern, 0, 1);

        for ($start = 0, $i = 1; $i < $n; ++$i) {
            $c = self::$_mbstringAvailable ? mb_substr($pattern, $i, 1, APP_CHARSET) : substr($pattern, $i, 1);
            if ($c !== $c0) {
                $ps[] = self::$_mbstringAvailable ? mb_substr($pattern, $start, $i - $start, APP_CHARSET) : substr($pattern, $start, $i - $start);
                $c0 = $c;
                $start = $i;
            }
        }
        $ps[] = self::$_mbstringAvailable ? mb_substr($pattern, $start, $n - $start, APP_CHARSET) : substr($pattern, $start, $n - $start);
        return $ps;
    }
629538
public function validatePattern($pattern)
    {
        $this->validator_attributes[] = 'data-parsley-pattern="' . $pattern . '"';

        $this->validator_checks['pattern'] = (int)$pattern;

        return $this;
    }
836143
public function get($pattern, $handler)
    {

        return $this->addRoute(
            new Route([Method::GET], $pattern, $handler)
        );
    }
884441
public function parse($route)
    {
        // reset param names
        $this->paramNames = [];

        // replace shortcuts
        $regex = strtr($route, $this->shortcuts);

        // replace param names that doesn't include shortcuts or regex
        $regex = preg_replace_callback('/{([a-zA-Z0-9]+)}/', [$this, 'replaceWithoutRegex'], $regex);

        // replace param names that includes shortcuts or regex
        $regex = preg_replace_callback('/{([a-zA-Z0-9]+):/', [$this, 'replaceWithRegex'], $regex);

        // replace ending grouping
        $regex = str_replace('}', ')', $regex);

        // fix slashes when optional params are present
        $regex = $this->fixOptionalSlashes($regex);

        // fix for handling trailing slashes
        $regex .= '(/)?';

        // return regex and param names
        return ['#^'. $regex .'$#', $this->paramNames];
    }
923305
public static function formatRegex($pattern)
    {
        if (strpos($pattern, '/') !== false
            && strpos($pattern, '\\/') === false
        ) {
            $pattern = str_replace('/', '\\/', $pattern);
        }
        return '/' . $pattern . '/';
    }
747265
public function grep($pattern)
    {
        $results = array_intersect_key($this->attributes, array_flip(
            RegexGuard::getGuard()->grep($pattern, array_keys($this->attributes))
        ));

        return new static($results);
    }
458649
protected function parseFormat($pattern)
	{
		static $formats=array();  // cache
		if(isset($formats[$pattern]))
			return $formats[$pattern];
		$tokens=array();
		$n=strlen($pattern);
		$isLiteral=false;
		$literal='';
		for($i=0;$i<$n;++$i)
		{
			$c=$pattern[$i];
			if($c==="'")
			{
				if($i<$n-1 && $pattern[$i+1]==="'")
				{
					$tokens[]="'";
					$i++;
				}
				elseif($isLiteral)
				{
					$tokens[]=$literal;
					$literal='';
					$isLiteral=false;
				}
				else
				{
					$isLiteral=true;
					$literal='';
				}
			}
			elseif($isLiteral)
				$literal.=$c;
			else
			{
				for($j=$i+1;$j<$n;++$j)
				{
					if($pattern[$j]!==$c)
						break;
				}
				$p=str_repeat($c,$j-$i);
				if(isset(self::$_formatters[$c]))
					$tokens[]=array(self::$_formatters[$c],$p);
				else
					$tokens[]=$p;
				$i=$j-1;
			}
		}
		if($literal!=='')
			$tokens[]=$literal;

		return $formats[$pattern]=$tokens;
	}
38179
private function buildQuery($pattern, $args)
    {

        if (count($args['parameters']) > 0) {

            $string = $pattern[0];
        } else {

            $string = $pattern[1];
        }

        if (preg_match_all("/:(\w+)/", $string, $match)) {

            $match = $match[0];
            $values = array_values($args);
            return str_replace($match, $values, $string);
        }
    }
1095056
protected function convertPattern($pattern)
    {
        $prefix = 0 === strpos($pattern, '!') ? '!' : '';
        $searchPattern = trim(ltrim($pattern, '!'), '/');
        $pattern = $prefix.$searchPattern;

        if (\in_array($searchPattern, array('*', '*.*'), true)) {
            $this->doAddPattern($prefix.'.*');
        } elseif (0 === strpos($searchPattern, '**/')) {
            $this->doAddPattern($prefix.'**/'.$searchPattern);
            $this->doAddPattern($prefix.substr($searchPattern, 3));
        } else {
            $this->convertPatternStep2($prefix, $searchPattern, $pattern);
        }

        return $pattern;
    }
615852
protected function getRegExpForPattern(string $pattern) : string
    {
        $patternReplaced = str_replace(['*', '?'], ["\nA\n", "\nQ\n"], $pattern);
        $patternReplaced = preg_quote($patternReplaced, '/');
        $patternReplaced = str_replace(["\nA\n", "\nQ\n"], ['.*', '.'], $patternReplaced);

        return '/^' . $patternReplaced . '$/';
    }
880056
protected function convert(/*# string */ $pattern)/*# : array */
    {
        // regex
        $groupname   = "\s*([a-zA-Z][a-zA-Z0-9_]*)\s*";
        $grouptype   = ":\s*([^{}]*(?:\{(?-1)\}[^{}]*)*)";
        $placeholder = sprintf("\{%s(?:%s)?\}", $groupname, $grouptype);
        $segmenttype = "[^/]++";

        // count placeholders
        $map = $m = [];
        if (preg_match_all('~'. $placeholder .'~x', $pattern, $m)) {
            $map = $m[1];
        }

        // full regex
        $result = preg_replace([
                '~' . $placeholder . '(*SKIP)(*FAIL) | \[~x',
                '~' . $placeholder . '(*SKIP)(*FAIL) | \]~x',
                '~\{' . $groupname . '\}~x',
                '~' . $placeholder . '~x',
            ], [
                '(?:',  // replace '['
                ')?',   // replace ']'
                '{\\1:' . $segmenttype . '}',   // add segementtype
                '(\\2)'                         // group it
            ], strtr('/' . trim($pattern, '/'), $this->shortcuts)
        );
        return [ $result, $map ];
    }
1301069
public function match($pattern, callable $to)
    {
        $route = new TopicRoute($pattern, $to);
        $controller = new Controller($route);
        $routeName = $controller->generateRouteName('');

        $controller->bind($routeName);

        $this->routeCollection->add($routeName, $route);

        return $controller;
    }