【问题标题】:glob exclude pattern全局排除模式
【发布时间】:2014-01-05 10:40:12
【问题描述】:

我有一个目录,里面有一堆文件:eee2314asd3442 ... 和 eph

我想使用glob 函数排除所有以eph 开头的文件。

我该怎么做?

【问题讨论】:

    标签: python glob


    【解决方案1】:

    要排除确切的单词,您可能需要实现 自定义正则表达式指令,然后您将在 glob 处理之前将其替换为空字符串。

    #!/usr/bin/env python3
    import glob
    import re
    
    # glob (or fnmatch) does not support exact word matching. This is custom directive to overcome this issue
    glob_exact_match_regex = r"\[\^.*\]"
    path = "[^exclude.py]*py"  # [^...] is a custom directive, that excludes exact match
    
    # Process custom directive
    try:  # Try to parse exact match direction
        exact_match = re.findall(glob_exact_match_regex, path)[0].replace('[^', '').replace(']', '')
    except IndexError:
        exact_match = None
    else:  # Remove custom directive
        path = re.sub(glob_exact_match_regex, "", path)
    paths = glob.glob(path)
    # Implement custom directive
    if exact_match is not None:  # Exclude all paths with specified string
        paths = [p for p in paths if exact_match not in p]
    
    print(paths)
    

    【讨论】:

      【解决方案2】:

      假设你有这样的目录结构:

      .
      ├── asd3442
      ├── eee2314
      ├── eph334
      ├── eph_dir
      │   ├── asd330
      │   ├── eph_file2
      │   ├── exy123
      │   └── file_with_eph
      ├── eph_file
      ├── not_eph_dir
      │   ├── ephXXX
      │   └── with_eph
      └── not_eph_rest
      

      您可以使用完整的 glob 通过 pathlib 和顶级目录的生成器过滤完整路径结果:

      i_want=(fn for fn in Path(path_to).glob('*') if not fn.match('**/*/eph*'))
      
      >>> list(i_want)
      [PosixPath('/tmp/test/eee2314'), PosixPath('/tmp/test/asd3442'), PosixPath('/tmp/test/not_eph_rest'), PosixPath('/tmp/test/not_eph_dir')]
      

      pathlib 方法match 使用glob 来匹配路径对象; glob '**/*/eph*' 是指向以'eph' 开头的文件的任何完整路径。

      或者,您可以将.name 属性与name.startswith('eph') 一起使用:

      i_want=(fn for fn in Path(path_to).glob('*') if not fn.name.startswith('eph'))
      

      如果你只想要文件,不要目录:

      i_want=(fn for fn in Path(path_to).glob('*') if fn.is_file() and not fn.match('**/*/eph*'))
      # [PosixPath('/tmp/test/eee2314'), PosixPath('/tmp/test/asd3442'), PosixPath('/tmp/test/not_eph_rest')]
       
      

      同样的方法适用于递归 glob:

      i_want=(fn for fn in Path(path_to).glob('**/*') 
                 if fn.is_file() and not fn.match('**/*/eph*'))
      
      # [PosixPath('/tmp/test/eee2314'), PosixPath('/tmp/test/asd3442'), 
         PosixPath('/tmp/test/not_eph_rest'), PosixPath('/tmp/test/eph_dir/asd330'), 
         PosixPath('/tmp/test/eph_dir/file_with_eph'), PosixPath('/tmp/test/eph_dir/exy123'), 
         PosixPath('/tmp/test/not_eph_dir/with_eph')]
      

      【讨论】:

        【解决方案3】:

        相比glob,我推荐pathlib。过滤一种模式非常简单。

        from pathlib import Path
        
        p = Path(YOUR_PATH)
        filtered = [x for x in p.glob("**/*") if not x.name.startswith("eph")]
        

        如果你想过滤更复杂的模式,你可以定义一个函数来做到这一点,就像:

        def not_in_pattern(x):
            return (not x.name.startswith("eph")) and not x.name.startswith("epi")
        
        
        filtered = [x for x in p.glob("**/*") if not_in_pattern(x)]
        

        使用该代码,您可以过滤所有以eph 或以epi 开头的文件。

        【讨论】:

          【解决方案4】:

          glob 的模式规则不是正则表达式。相反,它们遵循标准的 Unix 路径扩展规则。只有几个特殊字符:两个不同的通配符,并且支持字符范围[来自pymotw: glob – Filename pattern matching]。

          因此您可以排除一些带有模式的文件。
          例如,要使用 glob 排除清单文件(以 _ 开头的文件),您可以使用:

          files = glob.glob('files_path/[!_]*')
          

          【讨论】:

          • 这必须在官方文档中,请有人将其添加到docs.python.org/3.5/library/glob.html#glob.glob
          • 请注意,glob 模式不能直接满足 OP 提出的要求:仅排除以 eph 开头但可以以其他任何内容开头的文件。 [!e][!p][!h] 将过滤掉以 eee 开头的文件。
          • 请注意,如果您习惯于将 shell glob 排除项指定为 [^_],则这在 python 的 glob 中不起作用。必须使用!
          • @VitalyZdanevich 在 fnmatch 的文档中:docs.python.org/3/library/fnmatch.html#module-fnmatch
          【解决方案5】:

          如果字符的位置不重要,例如排除清单文件(无论在哪里找到_),使用globre - regular expression operations ,你可以使用:

          import glob
          import re
          for file in glob.glob('*.txt'):
              if re.match(r'.*\_.*', file):
                  continue
              else:
                  print(file)
          

          或者以更优雅的方式 - list comprehension

          filtered = [f for f in glob.glob('*.txt') if not re.match(r'.*\_.*', f)]
          
          for mach in filtered:
              print(mach)
          

          【讨论】:

            【解决方案6】:

            在遍历文件夹中的所有文件时跳过特定文件怎么样! 下面的代码将跳过所有以'eph'开头的excel文件

            import glob
            import re
            for file in glob.glob('*.xlsx'):
                if re.match('eph.*\.xlsx',file):
                    continue
                else:
                    #do your stuff here
                    print(file)
            

            通过这种方式,您可以使用更复杂的正则表达式模式来包含/排除文件夹中的一组特定文件。

            【讨论】:

              【解决方案7】:

              你可以扣除套数:

              set(glob("*")) - set(glob("eph*"))
              

              【讨论】:

              • 真正有趣的解决方案!但是我的情况会非常慢,读两遍。此外,如果网络目录上的文件夹内容很大,则会再次变慢。但无论如何,真的很方便。
              • 你的操作系统应该缓存文件系统请求,所以还不错:)
              • 我自己试过了,我刚得到 TypeError: unsupported operand type(s) for -: 'list' and 'list'
              • @TomBusby 尝试将它们转换为集合:set(glob("*")) - set(glob("eph*"))(注意“eph*”末尾的 *)
              • 顺便说一句,glob 返回列表而不是集合,但是这种操作只适用于集合,因此neutrinus 将其强制转换。如果您需要它保留一个列表,只需将整个操作包装在一个演员表中:list(set(glob("*")) - set(glob("eph")))
              【解决方案8】:

              您不能使用 glob 函数排除模式,glob 只允许 包含 模式。 Globbing syntax 非常有限(即使是[!..] 字符类必须 匹配一个字符,所以它是一个包含模式 用于不在该类中的每个字符)。

              您必须自己进行过滤;列表推导通常在这里工作得很好:

              files = [fn for fn in glob('somepath/*.txt') 
                       if not os.path.basename(fn).startswith('eph')]
              

              【讨论】:

              • 在此处使用iglob 以避免将完整列表存储在内存中
              • @Hardex:在内部,iglob 生成列表无论如何;您所做的只是懒惰地评估过滤器。这无助于减少内存占用。
              • @Hardex:如果您在 目录名称 中使用 glob,那么您就有了意义,那么在您迭代时最多将一个 os.listdir() 结果保存在内存中.但是somepath/*.txt 必须读取内存中一个目录中的所有文件名,然后将该列表缩减为仅匹配的那些。
              • 你说得对,这并不重要,但有 CPython 库存,glob.glob(x) = list(glob.iglob(x))。开销不大,但仍然很高兴知道。
              • 这不是迭代两次吗?一次通过文件获取列表,第二次通过列表本身?如果是这样,是否不可能在一次迭代中完成?
              【解决方案9】:

              正如接受的答案所述,您不能使用 glob 排除模式,因此以下是过滤 glob 结果的方法。

              公认的答案可能是最好的 Pythonic 做事方式,但如果您认为列表推导式看起来有点难看,并且想要让您的代码最大限度地 numpythonic(就像我所做的那样),那么您可以这样做(但请注意,这是可能比列表理解方法效率低):

              import glob
              
              data_files = glob.glob("path_to_files/*.fits")
              
              light_files = np.setdiff1d( data_files, glob.glob("*BIAS*"))
              light_files = np.setdiff1d(light_files, glob.glob("*FLAT*"))
              

              (在我的例子中,我有一些图像框架、偏置框架和平面框架都在一个目录中,我只想要图像框架)

              【讨论】:

                【解决方案10】:

                游戏晚了,但您也可以将 python filter 应用于 glob 的结果:

                files = glob.iglob('your_path_here')
                files_i_care_about = filter(lambda x: not x.startswith("eph"), files)
                

                或将 lambda 替换为适当的正则表达式搜索等...

                编辑:我刚刚意识到,如果您使用完整路径,startswith 将不起作用,因此您需要一个正则表达式

                In [10]: a
                Out[10]: ['/some/path/foo', 'some/path/bar', 'some/path/eph_thing']
                
                In [11]: filter(lambda x: not re.search('/eph', x), a)
                Out[11]: ['/some/path/foo', 'some/path/bar']
                

                【讨论】:

                  【解决方案11】:

                  更一般地说,要排除不符合某些 shell 正则表达式的文件,您可以使用模块 fnmatch

                  import fnmatch
                  
                  file_list = glob('somepath')    
                  for ind, ii in enumerate(file_list):
                      if not fnmatch.fnmatch(ii, 'bash_regexp_with_exclude'):
                          file_list.pop(ind)
                  

                  上面将首先从给定路径生成一个列表,然后弹出不满足具有所需约束的正则表达式的文件。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-05-27
                    • 2019-12-29
                    • 1970-01-01
                    • 2020-11-24
                    • 1970-01-01
                    • 2019-12-15
                    • 2012-09-06
                    相关资源
                    最近更新 更多