【问题标题】:Can PHP's glob() be made to find files in a case insensitive manner?可以使 PHP 的 glob() 以不区分大小写的方式查找文件吗?
【发布时间】:2014-01-22 14:53:55
【问题描述】:

我想要一个目录中的所有 CSV 文件,所以我使用

glob('my/dir/*.CSV')

但是,这不会找到具有小写 CSV 扩展名的文件。

可以使用

glob('my/dir/*.{CSV,csv}', GLOB_BRACE);

但是有没有办法允许所有混合大小写版本?还是这只是glob() 的限制?

【问题讨论】:

  • 请注意,glob() 在 Windows 中实际上是不区分大小写的(可能还有其他不区分大小写的文件系统)。
  • 那不是真的。 glob("*.CSV") 只会查找大写文件,而glob("*.csv") 只会查找小写文件。 --- 在 windows7 中使用 php 5.3.8 测试

标签: php case-insensitive glob


【解决方案1】:

全局模式支持字符范围:

glob('my/dir/*.[cC][sS][vV]')

【讨论】:

  • 但它不会也匹配任何以“.Csv”或“.CsV”结尾的文件吗?但这是一个支点:我正在寻找的是一种模式,它将以不区分大小写的方式(jpg、JPG、png、PNG 等)匹配所有图像文件。
  • @JohnK:“但是有没有办法允许所有混合大小写的版本?”
【解决方案2】:

你可以这样做

$files = glob('my/dir/*');

$csvFiles =  preg_grep('/\.csv$/i', $files);

【讨论】:

  • 非常干净和灵活。
  • 同意。看来您不能将 GLOB_BRACE 与字符范围结合起来,所以我最终使用 glob+preg_grep 一次对多种文件格式进行不区分大小写的搜索。感谢您的提示!
  • 这是 imo 最有用的解决方案。
  • 这会比普通且区分大小写的glob 更慢或占用更多内存吗?
  • @tjespe 理论上更慢且内存更多,因为有一个额外的迭代来过滤原始数组和创建的新数组。
【解决方案3】:

glob('my/dir/*.[cC][sS][vV]') 应该这样做。是的,有点丑。

【讨论】:

    【解决方案4】:

    你也可以全选后过滤掉文件

    foreach(glob('my/dir/*') as $file){
        $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
        if(!in_array($ext, array('csv'))){
            continue;
        }
        ... do stuff ...
    }
    

    就性能而言,如果文件夹中有 100 万个非 csv 文件,这可能不是最佳选择。

    【讨论】:

      【解决方案5】:

      此代码仅适用于获取图像且不区分大小写。

      图片列表:

      • image1.jpg
      • image2.JPG
      • image3.jpg
      • image4.GIF
      $imageOnly = '*.{[jJ][pP][gG],[jJ][pP][eE][gG],[pP][nN][gG],[gG][iI][fF]}'; $arr_files = (array) glob($path . $imageOnly, GLOB_BRACE);

      也许它看起来很丑,但你只需要声明一次 $imageOnly 并且可以在需要的地方使用它。您还可以声明 $jpgOnly 等。

      我什至做了一个函数来创建这个模式。

      /*--------------------------------------------------------------------------
       * create case insensitive patterns for glob or simular functions
       * ['jpg','gif'] as input
       * converted to: *.{[Jj][Pp][Gg],[Gg][Ii][Ff]}
       */
      function globCaseInsensitivePattern($arr_extensions = []) {
         $opbouw = '';
         $comma = '';
         foreach ($arr_extensions as $ext) {
             $opbouw .= $comma;
             $comma = ',';
             foreach (str_split($ext) as $letter) {
                 $opbouw .= '[' . strtoupper($letter) . strtolower($letter) . ']';
             }
         }
         if ($opbouw) {
             return '*.{' . $opbouw . '}';
         }
         // if no pattern given show all
         return '*';
      } // end function
      
      $arr_extensions = [
              'jpg',
              'jpeg',
              'png',
              'gif',
          ];
      $imageOnly = globCaseInsensitivePattern($arr_extensions);
      $arr_files = (array) glob($path . $imageOnly, GLOB_BRACE);
      

      【讨论】:

        【解决方案6】:

        您可以编写自己的不区分大小写的 glob。这是来自我写的一个个人网络图书馆:

        /** PHP has no case insensitive globbing
         * so we have to build our own.
         *
         * $base will be the initial part of the path which doesn't need case insensitive
         * globbing.
         * Suffix is similar - it will not be made insensitive
         * Make good use of $base and $suffix to keep $pat simple and fast in use.
         */
            function ciGlob($pat, $base = '', $suffix = '')
            {
                $p = $base;
                for($x=0; $x<strlen($pat); $x++)
                {
                    $c = substr($pat, $x, 1);
                    if( preg_match("/[^A-Za-z]/", $c) )
                    {
                        $p .= $c;
                        continue;
                    }
                    $a = strtolower($c);
                    $b = strtoupper($c);
                    $p .= "[{$a}{$b}]";
                }
                $p .= $suffix;
                return glob($p);
            }
        

        【讨论】:

          【解决方案7】:

          我听说有一个函数可以这样使用: 试试这是否适合你!

          <?php
          $pattern = sql_regcase("*.txt");
          glob($pattern);
          ?>
          

          【讨论】:

          • 有趣。但它的使用已被弃用。
          【解决方案8】:

          来到此链接以获取包含多个文件的 glob。虽然它对 OP 没有帮助,但它可能会帮助到这里的其他人。

          $file_type = 'csv,jpeg,gif,png,jpg';
          $i = '0';
          foreach(explode(",",$file_type) as $row){
              if ($i == '0') {
                  $file_types = $row.','.strtoupper($row);
              } else {
                  $file_types .= ','.$row.','.strtoupper($row);
              }
              $i++;
          }
          
          $files = glob($dir."*.{".$image_types."}",GLOB_BRACE);
          

          【讨论】:

          • $i'0'?为什么?
          • 0 是数组的第一个元素
          • 我的意思是,您将它用作循环索引,但将其定义为字符串。
          • 它被称为数字字符串和带有算术运算符的函数。
          【解决方案9】:

          根据 Alex 的提示,这通常会有所帮助:

          function glob_files ($d, $e)
          {
              $files = preg_grep ("/$e\$/i", glob ("$d/*"));
              sort ($files)
              return $files;
          }
          

          其中$d 是目录,$e 是扩展名。

          【讨论】:

            【解决方案10】:

            要使其适用于所有扩展,请使用:

            $extension = 'some_extension';
            glob('my/dir/*.preg_replace('/(\w)/e', "'['.strtoupper($1).strtolower($1).']'", $extension));
            

            【讨论】:

            • 我不能代表投票给你的人,但有几点(希望有帮助):(1)你的路径字符串缺少结束 ',以及(2)PCRE e (eval) 标志自 PHP 5.5 起已弃用并在 7 中删除,这两个标志都比此答案更旧。不鼓励使用它。
            • preg_replace() 是不必要的使用。您可以explode()map(),返回大小写变体,然后返回join()
            猜你喜欢
            • 1970-01-01
            • 2019-08-17
            • 1970-01-01
            • 2014-11-08
            • 2014-05-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多