Я хочу смочь проанализировать пути к файлам как этот:
/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
Прямо сейчас у меня есть a preg_match
оператор, который может разделить две альтернативы:
preg_match_all ("/\(([^)]*)\|([^)]*)\)/", $path_resource, $matches);
Кто-то мог дать мне подсказку, как расширить это для принятия неограниченного количества альтернатив (по крайней мере два)? Только относительно регулярного выражения, остальные я могу иметь дело с.
Правило:
Список должен запуститься с a (
и согласитесь с a )
Должен быть тот |
в списке (т.е. по крайней мере две альтернативы)
Любое другое возникновение (возникновение) (
или )
должны остаться нетронутыми.
Обновление: Я должен смочь также иметь дело с несколькими парами скобки, такими как:
/var/(www|www2)/index.(htm|html|php|shtml)
извините я немедленно не сказал это.
Обновление 2: Если Вы надеетесь делать то, что я пытаюсь сделать в файловой системе, то обратите внимание, что шарик () уже выводит эту функциональность из поля. Нет никакой потребности реализовать пользовательское решение. См. ответ @Gordon ниже для деталей.
Решение без регулярных выражений :)
<?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)'));
Возможно, я все еще не понимаю вопрос, но я предполагаю, что вы работаете через файловую систему, пока не нажмете один из файлов, и в этом случае вы можете сделать
$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.
Ответ дан, но это забавная загадка, и я просто не мог устоять.
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)!'));
может быть, это немного объясняет, почему мы так любим регулярные выражения;)
Не совсем то, что вы спрашиваете, но что плохого в том, чтобы просто взять то, что у вас есть, чтобы получить список (игнорируя | s), поместив его в переменную а затем взорвутся
на | s? Это даст вам массив, сколько бы элементов ни было (включая 1, если нет | подарка).
Думаю, вы ищете:
/ (([^ |] +) (| ([^ |] +)) +) /
В основном ставим разделитель '|' в повторяющийся узор.
Кроме того, согласно вашему третьему требованию, ваши слова должны состоять из «не трубы», а не «без скобок».
Кроме того, для этой задачи лучше использовать +
вместо *
. +
означает «хотя бы один». *
означает «ноль или больше».