相当于glob(),它可以与Array而不是File系统一起使用

时间:2010-12-09 10:09:29

标签: php regex algorithm amazon-s3

原始标题是算法,仅列出来自特定对象路径的目录/文件(S3,Google存储空间)

https://gist.github.com/9a353e1589ff3ce84c02

有人建议只在特定对象路径中列出目录/文件的算法吗?例如,ahostel.lt/img/应仅列出指南languages and psd, and files background.png, [..]。我的算法很冗长,并且使用了三个foreach周期,这对性能不利,但也许任何人都可以更好地了解如何使用正则表达式或其他替代方法来实现它。

我的系统在PHP上运行,但只要可以将其转换为PHP,一般对数就可以了。

换句话说,我正在寻找像glob()这样的算法,它可以用于数组而不是文件系统。

简化目录列表:https://gist.github.com/d0c3fa12d4b894938ba5

4 个答案:

答案 0 :(得分:4)

看起来你有一个简单的数组,所以这里有一个替代方法,它使用键上的正则表达式过滤数组。

// Matches only immediate files of ahostel.lt/img/
$pattern = '#^ahostel\.lt/img/[^/]+\.[^/]+$#D';
$keys    = preg_grep($pattern, array_keys($array));
$items   = array_intersect_key($array, array_flip($keys));

另一种方式,因为迭代器非常棒,而不编写定制的,将使用RegexIterator来完成过滤键的工作。然后,您只需遍历已过滤的迭代器,或使用iterator_to_array()获取仅包含过滤值的数组。

$items = new RegexIterator(
    new ArrayIterator($array),
    '#^ahostel\.lt/img/[^/]+\.[^/]+$#D',
    RegexIterator::MATCH,
    RegexIterator::USE_KEY
);

有许多不同的方法可以使用或创建迭代器过滤,甚至在accept()的{​​{1}}方法中使用fnmatch()之类的方法来使用像{一样的通配符模式{1}}。

FilterIterator

答案 1 :(得分:1)

  

换句话说,我正在寻找像glob()这样的算法,它可以用于数组而不是文件系统。

您可以使用ArrayIterator并将其包装到自定义FilterIterator

class CustomFilterIterator extends FilterIterator
{
    public function accept()
    {
        return strpos($this->key(), 'ahostel.lt/img/') === 0 &&
           pathinfo($this->key(), PATHINFO_EXTENSION) === 'png';
    }
}

accept方法必须返回一个布尔值。如果布尔值为TRUE,则考虑将当前迭代的元素包含在迭代中。在上面的例子中,任何不以'ahostel.lt / img /'开头并以png扩展名结尾的内容都将被忽略。您可以根据需要添加其他过滤条件。要访问密钥,请使用$this->key()。对于值,请使用$this->current()

用法codepad

$iterator = new CustomFilterIterator(new ArrayIterator($yourArray));

// to create a subset of the original array use
$filteredArray = iterator_to_array($iterator);

// or use good old foreach
foreach ($iterator as $path => $fileProperties) {
    var_dump($path, $fileProperties);
}

作为替代或补充,您可以使用RegexIterator

使用迭代器时的两个主要好处是重用和可测试性:迭代器可以堆叠,因此上面的CustomFilterIterator可以分为两个迭代器,如PathFilterExtensionFilter。然后,您只需将ArrayIterator包装到两个过滤器迭代器中,即可在顶部创建灵活的过滤器链。因为迭代器是类,所以可以在将迭代器作为依赖项的类中轻松地进行测试和模拟,这是将过滤逻辑放入foreach循环时无法做到的。

关于迭代器和SPL的其他资源:

答案 2 :(得分:1)

许多php程序员倾向于过度复杂化。一个简单的问题总是有一个简单的解决方案。

$result = array();
foreach($dir as $k => $v)
    if(strpos($k, 'ahostel.lt/img/') === 0)
        $result[$k] = $v;

这不仅比任何复杂的smart-alec代码更易读,而且速度更快。

答案 3 :(得分:0)

$already_included       = array();

    foreach($list as $key => $object)
    {
        $clean_key  = substr($key, strlen($uri));
        $explode    = explode('/', $clean_key);

        if(count($explode) >= 1 && !in_array($explode[0], $already_included))
        {
            $already_included[] = $explode[0];

            $files['directories'][] = array
            (
                'path'          => $uri . $explode[0] . '/',
                'name'          => $explode[0],
                'last_modified' => $object['last_modified'],
            );

        }

        if(substr_count($key, '/', $path_str_length) === 0)
        {
            $basename   = pathinfo($key, PATHINFO_BASENAME);

            if(strpos($basename, '.') !== FALSE)
            {
                $files['files'][]   = array
                (
                    'path'          => $key,
                    'name'          => $basename,
                    'size'          => $object['size'],
                    'last_modified' => $object['last_modified'],
                );
            }
            elseif(strrpos($basename, '_$folder$') !== FALSE)
            {
                $files['directories'][] = array
                (
                    'path'          => $key,
                    'name'          => substr($basename, 0, -9),
                    'last_modified' => $object['last_modified'],
                );
            }

        }
    }