如何为路由框架进行URL匹配正则表达式? [英] How to do URL matching regex for routing framework?

查看:629
本文介绍了如何为路由框架进行URL匹配正则表达式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经有一个匹配此模式的路由方法:

I already have a routing method that matches this pattern:

/hello/:name

将名称设置为动态路径,我想知道如何制作它:

that set name to be a dynamic path, I want to know how to make it:

/hello/{name}    

使用相同的正则表达式.像这样如何向其添加可选的斜杠?

with the same regex. How to add optional trailing slash to it, like this?

/hello/:name(/)

or

/hello/{name}(/)

这是我用于/hello/:name

@^/hello/([a-zA-Z0-9\-\_]+)$@D

regex是从PHP类自动生成的

The regex is auto generated from PHP class

private function getRegex($pattern){
        $patternAsRegex = "@^" . preg_replace('/\\\:[a-zA-Z0-9\_\-]+/', '([a-zA-Z0-9\-\_]+)', preg_quote($pattern)) . "$@D";
        return $patternAsRegex;
    }

如果路线为/hello/:name(/),我希望它与可选项目匹配,否则继续正常

If the route is /hello/:name(/) I want it to make the match with optional thing else continue normal

推荐答案

这将使用:name{name}参数以及可选的斜杠为$pattern路由创建正则表达式.另外,它还会添加?<name>以使参数更易于处理.

This will create a regular expression for the $pattern route with both :name and {name} parameters, as well as the optional slash. As a bonus, it will also add a ?<name> to make the parameter easier to handle down the line.

例如,路由模式/hello/:name(/)将获得正则表达式@^/hello/(?<name>[a-zA-Z0-9\_\-]+)/?$@D.与网址相匹配时,例如preg_match( <regex above>, '/hello/sarah', $matches),就会为您提供$matches['name'] == 'sarah'.

For example, a route pattern of /hello/:name(/) will get the regular expression @^/hello/(?<name>[a-zA-Z0-9\_\-]+)/?$@D. When matched with a URL, like preg_match( <regex above>, '/hello/sarah', $matches) that would give you $matches['name'] == 'sarah'.

在实际功能下可以找到一些测试.

There are some tests to be found below the actual function.

function getRegex($pattern){
    if (preg_match('/[^-:\/_{}()a-zA-Z\d]/', $pattern))
        return false; // Invalid pattern

    // Turn "(/)" into "/?"
    $pattern = preg_replace('#\(/\)#', '/?', $pattern);

    // Create capture group for ":parameter"
    $allowedParamChars = '[a-zA-Z0-9\_\-]+';
    $pattern = preg_replace(
        '/:(' . $allowedParamChars . ')/',   # Replace ":parameter"
        '(?<$1>' . $allowedParamChars . ')', # with "(?<parameter>[a-zA-Z0-9\_\-]+)"
        $pattern
    );

    // Create capture group for '{parameter}'
    $pattern = preg_replace(
        '/{('. $allowedParamChars .')}/',    # Replace "{parameter}"
        '(?<$1>' . $allowedParamChars . ')', # with "(?<parameter>[a-zA-Z0-9\_\-]+)"
        $pattern
    );

    // Add start and end matching
    $patternAsRegex = "@^" . $pattern . "$@D";

    return $patternAsRegex;
}

// Test it
$testCases = [
    [
        'route'           => '/hello/:name',
        'url'             => '/hello/sarah',
        'expectedParam'   => ['name' => 'sarah'],
    ],
    [
        'route'           => '/bye/:name(/)',
        'url'             => '/bye/stella/',
        'expectedParam'   => ['name' => 'stella'],
    ],
    [
        'route'           => '/find/{what}(/)',
        'url'             => '/find/cat',
        'expectedParam'   => ['what' => 'cat'],
    ],
    [
        'route'           => '/pay/:when',
        'url'             => '/pay/later',
        'expectedParam'   => ['when' => 'later'],
    ],
];

printf('%-5s %-16s %-39s %-14s %s' . PHP_EOL, 'RES', 'ROUTE', 'PATTERN', 'URL', 'PARAMS');
echo str_repeat('-', 91), PHP_EOL;

foreach ($testCases as $test) {
    // Make regexp from route
    $patternAsRegex = getRegex($test['route']);

    if ($ok = !!$patternAsRegex) {
        // We've got a regex, let's parse a URL
        if ($ok = preg_match($patternAsRegex, $test['url'], $matches)) {
            // Get elements with string keys from matches
            $params = array_intersect_key(
                $matches,
                array_flip(array_filter(array_keys($matches), 'is_string'))
            );

            // Did we get the expected parameter?
            $ok = $params == $test['expectedParam'];

            // Turn parameter array into string
            list ($key, $value) = each($params);
            $params = "$key = $value";
        }
    }

    // Show result of regex generation
    printf('%-5s %-16s %-39s %-14s %s' . PHP_EOL,
        $ok ? 'PASS' : 'FAIL',
        $test['route'], $patternAsRegex,
        $test['url'],   $params
    );
}

输出:

RES   ROUTE            PATTERN                                 URL            PARAMS
-------------------------------------------------------------------------------------------
PASS  /hello/:name     @^/hello/(?<name>[a-zA-Z0-9\_\-]+)$@D   /hello/sarah   name = sarah
PASS  /bye/:name(/)    @^/bye/(?<name>[a-zA-Z0-9\_\-]+)/?$@D   /bye/stella/   name = stella
PASS  /find/{what}(/)  @^/find/(?<what>[a-zA-Z0-9\_\-]+)/?$@D  /find/cat      what = cat
PASS  /pay/:when       @^/pay/(?<when>[a-zA-Z0-9\_\-]+)$@D     /pay/later     when = later

这篇关于如何为路由框架进行URL匹配正则表达式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆