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}(/)
This is the regex I use for /hello/:name
这是我用于/ hello /:name的正则表达式
@^/hello/([a-zA-Z0-9\-\_]+)$@D
The regex is auto generated from PHP class
正则表达式是从PHP类自动生成的
private function getRegex($pattern){
$patternAsRegex = "@^" . preg_replace('/\\\:[a-zA-Z0-9\_\-]+/', '([a-zA-Z0-9\-\_]+)', preg_quote($pattern)) . "$@D";
return $patternAsRegex;
}
If the route is /hello/:name(/)
I want it to make the match with optional thing else continue normal
如果路由是/ hello /:name(/)我希望它与可选的东西匹配,则继续正常
2 个解决方案
#1
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.
这将为$ pattern路由创建一个正则表达式,其中包含:name和{name}参数,以及可选的斜杠。作为奖励,它还会添加一个?
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'
.
例如,/ hello /:name(/)的路由模式将获得正则表达式@ ^ / hello /(?
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
);
}
Output:
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
#2
Simply replace your regex with this for optional /
:
只需将此正则表达式替换为可选/:
@^/hello/([a-zA-Z0-9-_]+)/?$@
#1
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.
这将为$ pattern路由创建一个正则表达式,其中包含:name和{name}参数,以及可选的斜杠。作为奖励,它还会添加一个?
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'
.
例如,/ hello /:name(/)的路由模式将获得正则表达式@ ^ / hello /(?
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
);
}
Output:
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
#2
Simply replace your regex with this for optional /
:
只需将此正则表达式替换为可选/:
@^/hello/([a-zA-Z0-9-_]+)/?$@