提问人:Pekka 提问时间:3/29/2010 最后编辑:Pekka 更新时间:3/29/2010 访问量:912
正则表达式可匹配无限数量的选项
Regular Expression to match unlimited number of options
问:
我希望能够解析这样的文件路径:
/var/www/index.(htm|html|php|shtml)
放入有序数组中:
array("htm", "html", "php", "shtml")
然后生成备选方案列表:
/var/www/index.htm
/var/www/index.html
/var/www/index.php
/var/www/index.shtml
现在,我有一个声明可以拆分两个选项:preg_match
preg_match_all ("/\(([^)]*)\|([^)]*)\)/", $path_resource, $matches);
有人可以给我一个指示,如何扩展它以接受无限数量的替代方案(至少两个)?关于正则表达式,其余的我可以处理。
规则是:
列表需要以 a 开头,以
(
)
列表中必须有一个(即至少两个备选方案)
|
任何其他事件或将保持不变。
(
)
更新:我还需要能够处理多个括号对,例如:
/var/(www|www2)/index.(htm|html|php|shtml)
对不起,我没有马上说。
更新2:如果你想在文件系统中做我想做的事情,那么请注意 glob() 已经带来了这个功能。无需实现自定义解决方案。有关详细信息,请参阅下面的 @Gordon 的回答。
答:
不完全是你要问的,但是只拿你所要得到的列表(忽略|s),把它放到一个变量中,然后在|s上爆炸
有什么问题?这将为您提供一个包含任意数量的项目的数组(如果没有 | 存在,则包括 1 个)。
我想你正在寻找:
/(([^|]+)(|([^|]+))+)/
基本上,将拆分器“|”放入重复模式中。
此外,根据你的第三个要求,你的话应该由“不是管道”而不是“不是parens”组成。
另外,更喜欢这个问题。 表示“至少一个”。 表示“零或更多”。+
*
+
*
评论
非正则表达式解决方案:)
<?php
$test = '/var/www/index.(htm|html|php|shtml)';
/**
*
* @param string $str "/var/www/index.(htm|html|php|shtml)"
* @return array "/var/www/index.htm", "/var/www/index.php", etc
*/
function expand_bracket_pair($str)
{
// Only get the very last "(" and ignore all others.
$bracketStartPos = strrpos($str, '(');
$bracketEndPos = strrpos($str, ')');
// Split on ",".
$exts = substr($str, $bracketStartPos, $bracketEndPos - $bracketStartPos);
$exts = trim($exts, '()|');
$exts = explode('|', $exts);
// List all possible file names.
$names = array();
$prefix = substr($str, 0, $bracketStartPos);
$affix = substr($str, $bracketEndPos + 1);
foreach ($exts as $ext)
{
$names[] = "{$prefix}{$ext}{$affix}";
}
return $names;
}
function expand_filenames($input)
{
$nbBrackets = substr_count($input, '(');
// Start with the last pair.
$sets = expand_bracket_pair($input);
// Now work backwards and recurse for each generated filename set.
for ($i = 0; $i < $nbBrackets; $i++)
{
foreach ($sets as $k => $set)
{
$sets = array_merge(
$sets,
expand_bracket_pair($set)
);
}
}
// Clean up.
foreach ($sets as $k => $set)
{
if (false !== strpos($set, '('))
{
unset($sets[$k]);
}
}
$sets = array_unique($sets);
sort($sets);
return $sets;
}
var_dump(expand_filenames('/(a|b)/var/(www|www2)/index.(htm|html|php|shtml)'));
评论
(html|php(4|5))
也许我仍然没有得到这个问题,但我的假设是你正在运行文件系统,直到你命中其中一个文件,在这种情况下,你可以这样做
$files = glob("$path/index.{htm,html,php,shtml}", GLOB_BRACE);
生成的数组将包含与您的扩展名匹配的任何文件($path或无)。如果需要按特定的扩展名顺序包含文件,则可以使用有序列表的扩展名来覆盖数组,例如foreach
foreach(array('htm','html','php','shtml') as $ext) {
foreach($files as $file) {
if(pathinfo($file, PATHINFO_EXTENSION) === $ext) {
// do something
}
}
}
编辑:是的,您可以在 glob 中拥有多个大括号。
评论
GLOB_BRACE
答案已经给出,但这是一个有趣的谜题,我简直无法抗拒
function expand_filenames2($str) {
$r = array($str);
$n = 0;
while(preg_match('~(.*?) \( ( \w+ \| [\w|]+ ) \) (.*) ~x', $r[$n++], $m)) {
foreach(explode('|', $m[2]) as $e)
$r[] = $m[1] . $e . $m[3];
}
return array_slice($r, $n - 1);
}
print_r(expand_filenames2('/(a|b)/var/(ignore)/(www|www2)/index.(htm|html|php|shtml)!'));
也许这在一定程度上解释了为什么我们;)那么喜欢正则表达式
评论
\w
\w\d.
评论
|