正则表达式用于 PHP 中的路由匹配


Regex for route matching in PHP

我正在用PHP开发我的迷你url路由器。到目前为止,我已经有了正则表达式,用于提取包含在{}中的url中的变量(通过查看Symfony的路由器代码(:

public function parse($pattern)
{
    $matches = '';
    $variables = array();
    $pos = 0;
    preg_match_all('#'{'w+'}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
    foreach ($matches as $match) 
    {
        $varName = substr($match[0][0], 1, -1);
        if(is_numeric($varName)) {
            throw new Exception('Argument cannot be a number');
        }
        if (in_array($varName, $variables)) {
            throw new 'LogicException(sprintf('More then one occurrence of variable name "%s".', $varName));
        }
        $variables[] = $varName;
    }
    return ['variables' => $variables];
}

所以这个方法提取变量,现在我需要一个正则表达式来匹配路由的模式与 url。我开始学习正则表达式,但我仍然不太好理解这一点。

这将起作用: '/hello'/{?([^'/}]+)}?

(至少在您提供的示例上是这样:(

/hello/{name} /hello/Sam

解释

  • '/是逃脱的/
  • hello找到hello,以防你没有意识到。
  • {?找到一个{,如果有的话。
  • ([^'/}]+)找到所有不是/}
  • 的东西
  • }?找到一个},如果有的话。

对于任何可能感兴趣的人,我明白了,多亏了劳雷尔的回答。

这是该方法的更新版本,它仍然需要一些工作:

$matches = '';
    $variables = array();
    $pos = 0;
    $reg = '#';
    $nextText = '';
    preg_match_all('#'{'w+'}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
    foreach ($matches as $match) 
    {
        $varName = substr($match[0][0], 1, -1);
        $precedingText = substr($pattern, $pos, $match[0][1] - $pos);
        $pos = $match[0][1] + strlen($match[0][0]);
        $nxt = $pos - strlen($pattern);
        if($nxt == 0) $nxt = strlen($pattern); 
        $nextText = substr($pattern, $nxt);
        //$precedingText = substr($precedingText, 1, -1);
        $precSegments = explode('/', $precedingText);
        $precSegments = array_splice($precSegments, 1);
        //$temp = 5; 
        echo 'nxt ' . $nextText . '<><br>'; 
        if(strlen($precedingText) > 1)
        {       
            foreach($precSegments as $key => $value)
            {   
                $reg .= ''/';
                $reg .= $value; 
            }
            $reg .= '{?([^'/}]+)}?';  
        }
        else
        {
            $reg .= '{?([^'/}]+)}?';
        }
        $nextText = str_replace('/', ''/', $nextText);
        if(is_numeric($varName)) {
            throw new Exception('Argument cannot be a number');
        }
        if (in_array($varName, $variables)) {
            throw new 'LogicException(sprintf('More then one occurrence of variable name "%s".', $varName));
        }
        $variables[] = $varName;    
    }
    if(count($matches) < 1)
    {
        $reg .= str_replace('/', ''/', $pattern);
    }
    $reg = $reg . $nextText;
    $reg .= '#';
    if($pattern == '/')
    {
        $reg = '#^['/]+$#';
    }
    return ['variables' => $variables, 'regex' => $reg];