如何在PHP中使用RegexIterator

我还没有find一个很好的例子,如何使用PHP的RegexIteratorrecursion遍历目录。

最终的结果将是我想指定一个目录,并find一些给定的扩展名中的所有文件。 例如只说html / php扩展。 此外,我想过滤出types为.Trash-0,.Trash-500等文件夹。

<?php $Directory = new RecursiveDirectoryIterator("/var/www/dev/"); $It = new RecursiveIteratorIterator($Directory); $Regex = new RegexIterator($It,'/^.+\.php$/i',RecursiveRegexIterator::GET_MATCH); foreach($Regex as $v){ echo $value."<br/>"; } ?> 

是我到目前为止,但导致:致命错误:未收到的exception'UnexpectedValueException'消息'RecursiveDirectoryIterator :: __构造(/media/hdmovies1/.Trash-0)

有什么build议么?

有几种不同的方式来做这样的事情,我会给你两个快速的方法供你select:快速和肮脏的,而不是更长,更肮脏(但是,这是一个星期五晚上,所以我们被允许去有点疯狂)。

1.快速(而且脏)

这涉及到只需编写一个正则expression式(可以拆分成多个)来使用一次快速筛选文件集合。

(只有两个注释行对这个概念非常重要。)

 $directory = new RecursiveDirectoryIterator(__DIR__); $flattened = new RecursiveIteratorIterator($directory); // Make sure the path does not contain "/.Trash*" folders and ends eith a .php or .html file $files = new RegexIterator($flattened, '#^(?:[AZ]:)?(?:/(?!\.Trash)[^/]+)+/[^/]+\.(?:php|html)$#Di'); foreach($files as $file) { echo $file . PHP_EOL; } 

这种方法有许多问题,尽pipe实现只是一个单一的内容(尽pipe正则expression式可能是一个破译的痛苦)。

2.less快(而且less脏)

一个更可重用的方法是创build一个定制的filter(使用正则expression式,或任何你喜欢的!)来减less在初始RecursiveDirectoryIterator中的可用项目列表,只有那些你想要的。 以下仅仅是一个例子,只是为了你的扩展RecursiveRegexIterator

我们从一个基类开始,它的主要工作是保持我们要过滤的正则expression式,其他所有东西都被推迟到RecursiveRegexIterator 。 请注意,该类是abstract因为它实际上并没有任何有用的事情:实际的过滤是由两个类来完成的,这两个类将扩展这个类。 此外,它可能被称为FilesystemRegexFilter但没有什么强迫它(在这个级别)来过滤文件系统相关的类(如果我不那么昏昏欲睡,我会select一个更好的名字)。

 abstract class FilesystemRegexFilter extends RecursiveRegexIterator { protected $regex; public function __construct(RecursiveIterator $it, $regex) { $this->regex = $regex; parent::__construct($it, $regex); } } 

这两个类是非常基本的filter,分别作用于文件名和目录名。

 class FilenameFilter extends FilesystemRegexFilter { // Filter files against the regex public function accept() { return ( ! $this->isFile() || preg_match($this->regex, $this->getFilename())); } } class DirnameFilter extends FilesystemRegexFilter { // Filter directories against the regex public function accept() { return ( ! $this->isDir() || preg_match($this->regex, $this->getFilename())); } } 

为了实践这些,下面的代码recursion地遍历脚本所在目录的内容(随意编辑!)并过滤出.Trash文件夹(通过确保文件夹名称特制的正则expression式匹配 ) ,只接受PHP和HTML文件。

 $directory = new RecursiveDirectoryIterator(__DIR__); // Filter out ".Trash*" folders $filter = new DirnameFilter($directory, '/^(?!\.Trash)/'); // Filter PHP/HTML files $filter = new FilenameFilter($filter, '/\.(?:php|html)$/'); foreach(new RecursiveIteratorIterator($filter) as $file) { echo $file . PHP_EOL; } 

特别值得注意的是,由于我们的滤波器是recursion的,所以我们可以select如何遍历它们。 例如,我们可以很容易地将自己限制为仅扫描最多2层(包括起始文件夹),方法是:

 $files = new RecursiveIteratorIterator($filter); $files->setMaxDepth(1); // Two levels, the parameter is zero-based. foreach($files as $file) { echo $file . PHP_EOL; } 

对于更多专门的过滤需求(例如文件大小,全path长度等),添加更多的filter(通过实例化更多不同正则expression式的过滤类;或创build新的过滤类)也是非常容易的。

PS嗯这个答案唠叨了一下; 我试图尽可能保持简洁(甚至去除大片的超级喋喋不休)。 如果最终的结果让答案不连贯,我们抱歉。

文档确实没有太大的帮助。 在这里使用正则expression式的'不匹配'有一个问题,但我们将首先举例说明一个工作示例:

 <?php //we want to iterate a directory $Directory = new RecursiveDirectoryIterator("/var/dir"); //we need to iterate recursively $It = new RecursiveIteratorIterator($Directory); //We want to stop decending in directories named '.Trash[0-9]+' $Regex1 = new RecursiveRegexIterator($It,'%([^0-9]|^)(?<!/.Trash-)[0-9]*$%'); //But, still continue on doing it **recursively** $It2 = new RecursiveIteratorIterator($Regex1); //Now, match files $Regex2 = new RegexIterator($It2,'/\.php$/i'); foreach($Regex2 as $v){ echo $v."\n"; } ?> 

问题是不匹配.Trash[0-9]{3}部分:我知道如何去反向匹配目录的唯一方法是匹配string$的末尾,然后用lookbehind (?<!/foo) “,如果它没有在”/ foo“之前。

但是,由于.Trash[0-9]{1,3}不是固定长度,我们不能用它作为后向断言。 不幸的是,RegexIterator没有“反向匹配”。 但也许有更多的正则expression式的人,然后我知道如何匹配任何string不以.Trash[0-9]+


编辑 :得到它作为一个正则expression式'%([^0-9]|^)(?<!/.Trash-)[0-9]*$%'将做的伎俩。

对salathe的改进,将是忘记自定义的抽象类。 只需在PHP中使用良好的OOP,直接扩展RecursiveRegexIterator即可:

这是文件filter

 class FilenameFilter extends RecursiveRegexIterator { // Filter files against the regex public function accept() { return ! $this->isFile() || parent::accept(); } } 

和目录filter

 class DirnameFilter extends RecursiveRegexIterator { // Filter directories against the regex public function accept() { return ! $this->isDir() || parent::accept(); } }