在PHP的字符串中替换命名为'parameters'的字符串 [英] Replacing named 'parameters' within a string in PHP
问题描述
感谢@SJFrK,我的问题已解决.下一堂课可以让我做我需要的事情.问题紧随班级.
Thanks to @SJFrK, my issue has been solved. The following class allows me to do what I need. The question follows the class.
class Redirects
{
/*
|--------------------------------------------------------------------------
| Placeholder Types
|--------------------------------------------------------------------------
|
| An array of placeholder types thatalow specific characters in a source
| route or URL.
|
*/
private static $placeholders = array(
':all' => '.*',
':alpha' => '[a-z]+',
':alphanum' => '[a-z0-9]+',
':any' => '[a-z0-9\.\-_%=]+',
':num' => '[0-9]+',
':segment' => '[a-z0-9\-\_]+',
':segments' => '[a-z0-9\-\_\/]+',
);
/*
|--------------------------------------------------------------------------
| Computed Replacements
|--------------------------------------------------------------------------
|
| An array that contains converted source placeholders.
|
*/
private static $computed_replacements = array();
/*
|--------------------------------------------------------------------------
| Computed Replacements
|--------------------------------------------------------------------------
|
| Class-scoped string that contains a replacement route or URL from
| site.redirects.
|
*/
private static $destination;
/**
* Check for a redirect. If it exists, then redirect to it's computed replacement.
*
* @return Response
*/
public static function redirect()
{
// Only do this if redirects have been defined.
if (Config::has('site.redirects') && count(Config::get('site.redirects') > 0))
{
$route = URI::current();
// Get the available placeholders from static::$placeholders and
// convert them into applicable options for the pattern.
$available_placeholders = '';
foreach (static::$placeholders as $placeholder => $expression)
$available_placeholders .= ltrim("$placeholder|", ':');
$available_placeholders = rtrim($available_placeholders, '|');
// Define the pattern.
$pattern = '/\((\w+):('.$available_placeholders.')\)/';
// Get the redirects.
$redirects = Config::get('site.redirects');
// For each redirect, convert all the place holders and resulting
// values, and check for a match. If one exists, then redirect to it.
foreach ($redirects as $from => $to) {
static::$computed_replacements = array();
static::$destination = $to;
$from = rtrim($from, '/');
$to = rtrim($to, '/');
// Convert the placeholders in $from (if any)
$converted_placeholders = preg_replace_callback($pattern, function($captures) {
static::$computed_replacements[] = $captures[1];
return '('.static::$placeholders[":{$captures[2]}"].')';
}, $from);
// Get the replacements
$converted_replacements = preg_replace_callback("#^{$converted_placeholders}$#i", function($captures) {
$output = static::$destination;
for ($c = 1, $n = count($captures); $c < $n; ++$c)
{
$value = array_shift(static::$computed_replacements);
$output = str_replace("<$value>", $captures[$c], $output);
}
return $output;
}, $route);
// If the current route matches the converted expression, then redirect.
if (preg_match("!^{$converted_placeholders}$!i", $route))
return Redirect::to($converted_replacements, 301)
->with('moved-from', $route)
->with('moved-from-rule', "'$from': '".static::$destination."'");
}
}
else return;
}
}
简介
我正在用 Laravel (FTW)编写静态网站捆绑包,并且遇到了一些问题似乎无法绕开.
INTRODUCTION
I'm in the process of writing a static website bundle in Laravel (FTW), and have come accross something I can't seem to get around.
该应用程序包含一个配置文件(config/site.php
),除其他事项外,该文件还包含一组重定向查找.这个想法是检查每个查找URI中的匹配项,然后重定向到替换URI(当然是301重定向)-对于将静态HTML站点移到我的包中的用户很有用.
The app contains a configuration file (config/site.php
), which - among other things - contains an array of redirect lookups. The idea is to check for a match in each lookup URI, and then redirect to the replacement URI (with a 301 redirect, of course) - useful for those moving a static HTML site over to my bundle.
数组的格式为:
'redirects' => array(
'<source>' => '<destination>'
)
在<source>
中,用户可以包括以下内容:
Within the <source>
, the user can include the following:
- 正则表达式
- Laravel样式的占位符:
(:any)
,(:all)
,(:num)
或(:alpha)
-我添加了最后一个.
- Regular Expressions
- Laravel-style placeholders:
(:any)
,(:all)
,(:num)
, or(:alpha)
- I added that last one.
例如,用户可以使用以下重定向(请注意,我选择对<destination>
使用角括号,因为它更具美感-将其转换回其正则表达式等效项[请参见下面的类] ):
For example, the user could use the following redirect (note that I have chosen to use angular parenthises for the <destination>
as it a little more aesthetic - it is converted back down to its regex equivalent [see the class below]):
'(:all).html' => '<1>'
这会将任何以.html
结尾的页面定向到不包含该页面的路由.例如:http://example.com/about.html
将重定向到http://example.com/about
.
This would direct any page ending with .html
to a route that does not contain it. Example: http://example.com/about.html
would redirect to http://example.com/about
.
我希望能够为每个参数命名"以便于阅读(和舒适的编码).我想做的是在<source>
中命名每个占位符(当然这是可选的),并定义一个占位符类型.例如:
I would like to be able to 'name' each parameter for easy-reading (and pleasant coding). What I'd like to do is name each placeholder in <source>
(this is optional, of course), AND define a placeholder-type. For example:
'(name:all).html' => '<name>'
现在,考虑到可以命名占位符 ,它们自然可以在<destination>
内以任何顺序排列(例如,注意目标URI中的顺序更改):
Now, considering that the placeholders could be named, they could naturally be in any order within the <destination>
, for example (note the order changes in the destination URI):
'Products/(name:any)-(category:any)-(id:num).html' => 'products/<category>/<id>/<name>/overview'
使用常规的占位符语法,我可以将其解释为:
Using the regular placeholder syntax, I could interpret this as:
'Products/(:any)-(:any)-(:num).html' => 'products/<2>/<3>/<1>'
无论如何这都是后备-我需要找出如何使用preg_replace
将名称替换为其相应的捕获组.但是似乎无法使用命名的参数/捕获:
This is the fallback anyway - I'd need to find out how to replace the names with their corresponding capture groups using preg_replace
. But it seems to not be possible using named parameters/captures:
一种简单的方法是在preg_replace
中使用命名参数,但是(据我所知)PHP不支持它.
An easy route would be by using named parameters in preg_replace
, but (as I understand this) PHP does not support it.
使用这种方法将使我能够使用相同种类的替换工具来完成任务-因此无法使用它会有点令人失望.
Using this method would enable me to use the same kind of replacement tools to get the task done - so not having it available is a little disappointing.
尽管如此,我还是很高兴回复到稍微复杂一点的东西(无论如何,这是一件好事).问题是,我不知道如何-而且解决方案还没有到我这里.我看过 Silex RouteCompiler
类,但是并没有完全理解.我认为,考虑到Laravel的主干是基于Symfony组件集(与Silex十分相似),可能有更好的方法来完成我需要的工作.
Nonetheless, I am happy to revert to something a little more complex (which is a good thing, anyway). Thing is, I have no idea how - and a solution is just not coming to me. I have had a look at the Silex RouteCompiler
class, but do not understand it fully. I feel that, considering the backbone of Laravel is built upon the Symfony component-set (much like Silex), there may be a better way to accomplish what I need.
有人有相同的要求,也许找到了解决方案?这里的任何帮助简直是太棒了!预先感谢.
Has anyone had the same kind of requirements, and perhaps found a solution? Any help here would be simply awesome! Thanks in advance.
这是处理重定向的类的源.我只需在我的routes.php
文件中调用Redirects::handle()
.
Here's the source to the class that handles the redirects. I simply call Redirects::handle()
in my routes.php
file.
class Redirects
{
private static $placeholders = array(
':any' => '[a-zA-Z0-9\.\-_%=]+',
':num' => '[0-9]+',
':alpha' => '[a-z]+', //added
':all' => '.*',
);
private static $replacement_identifiers = array(
'(\<([0-9]+)\>)' => '$$1',
);
/**
* Create the applicable regex placeholders
*
* @param string &$from
* @param string &$to
* @return void
*/
protected static function placeholders(string &$from, string &$to)
{
// Replace the <source> with a match expression
foreach (static::$placeholders as $placeholder => $expression)
$from = str_replace("({$placeholder})", "({$expression})", $from);
// Replace the <destination> with a replacement expression
foreach (static::$replacement_identifiers as $identifier => $expression)
if (preg_match($identifier, $to))
$to = preg_replace($identifier, $expression, $to);
}
/**
* Return the response of any redirects, or void if none
*
* @return Response|void
*/
public static function handle()
{
$route = URI::current();
if (Config::has('site.redirects'))
{
$redirects = Config::get('site.redirects');
foreach ($redirects as $from => $to) {
$from = rtrim($from, '/');
static::placeholders($from, $to);
if (preg_match("!^{$from}$!i", $route))
{
if (strpos($to, '$') !== false and strpos($from, '(') !== false)
$to = preg_replace("!^{$from}$!i", $to, $route);
return Redirect::to($to, 301)->with('Moved-From', $route);
}
else return;
}
}
else return;
}
}
推荐答案
这是一个可以满足您需求的测试用例,也许您可以将其合并到您的类中?:
This is a test-case case that does what you want, maybe you can incorporate this into your class?:
<?php
class Redirects {
private static $placeholders = array(
':any' => '[a-zA-Z0-9\.\-_%=]+',
':num' => '[0-9]+',
':alpha' => '[a-z]+', //added
':all' => '.*',
);
private static $tmp;
private static $tmpValue;
public static function handle() {
$case = array('Products/(name:any)-(category:any)-(id:num).html' => 'products/<category>/<id>/<name>/overview');
$test = 'Products/productName-categoryName-123.html'; // products/categoryName/123/productName/overview
$pattern = '/\(\s*?(\w*?)\s*?:\s*?(\w*?)\s*?\)/';
foreach ($case as $k => $v) {
self::$tmp = array();
self::$tmpValue = $v;
$step1 = preg_replace_callback($pattern, array(self, 'replace_step1'), $k);
$step2 = preg_replace_callback('#' . $step1 . '#', array(self, 'replace_step2'), $test);
print 'case: ' . $k . '<br>';
print 'step1: ' . $step1 . '<br>';
print 'step2: ' . $step2 . '<br>';
}
}
private static function replace_step1($matches) {
self::$tmp[] = $matches[1];
return '(' . self::$placeholders[':' . $matches[2]] . ')';
}
private static function replace_step2($matches) {
$str = self::$tmpValue;
for ($i = 1, $n = count($matches); $i < $n; ++$i) {
$value = array_shift(self::$tmp);
$str = str_replace('<' . $value . '>', $matches[$i], $str);
}
return $str;
}
}
Redirects::handle();
它首先用真实的PREG占位符替换您命名的占位符,并将它们存储在数组$tmp
中.然后,它会检查测试字符串$test
是否与该模式$step1
匹配,并根据$tmp
数组替换它们.
It first replaces your named placeholders with the real PREG placeholders and stores them in an array $tmp
. It then checks the test-string $test
if it matches that pattern $step1
and replaces them according to the $tmp
array.
这篇关于在PHP的字符串中替换命名为'parameters'的字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!