【问题标题】:grep -r in pythongrep -r 在 python 中
【发布时间】:2009-12-07 22:03:01
【问题描述】:

我想在 python 函数中实现 unix 命令“grep -r”。我知道commands.getstatusoutput(),但现在我不想使用它。我想出了这个:

def grep_r (str, dir):
    files = [ o[0]+"/"+f for o in os.walk(dir) for f in o[2] if os.path.isfile(o[0]+"/"+f) ]
    return [ l for f in files for l in open(f) if str in l ]

但这当然不使用正则表达式,它只是检查'str'是否是'l'的子字符串。所以我尝试了以下方法:

def grep_r (pattern, dir):
    r = re.compile(pattern)
    files = [ o[0]+"/"+f for o in os.walk(dir) for f in o[2] if os.path.isfile(o[0]+"/"+f) ]
    return [ l for f in files for l in open(f) if r.match(l) ]

但这不起作用,即使在前一个函数有的地方,它也没有给我任何匹配。发生了什么变化?我可以把它分成一堆嵌套循环,但我更感兴趣的是简洁而不是可读。

【问题讨论】:

    标签: python grep


    【解决方案1】:

    您可能想要search() 而不是match() 来捕获行中间的匹配项,如http://docs.python.org/library/re.html#matching-vs-searching 中所述

    此外,您的代码的结构和意图非常隐蔽。我已经把它python化了。

    def grep_r (pattern, dir):
        r = re.compile(pattern)
        for parent, dnames, fnames in os.walk(dir):
            for fname in fnames:
                filename = os.path.join(parent, fname)
                if os.path.isfile(filename):
                    with open(filename) as f:
                        for line in f:
                            if r.search(line):
                                yield line
    

    【讨论】:

    • 是的,我的几乎不可读,自从我阅读 norvig.com/spell-correct.html">this Peter Norvig 的文章后,我一直在我的代码中添加那些“i for i in some_generator”语句...
    • 哦,想要使用强大的抽象是很自然的!在列表推导出现之前,我曾经对 map() 和 reduce() 进行了可怕的多行构造——我真的很喜欢“对所有这些都做这个”的想法,而不是“好吧,得到下一个然后做......好吧,得到下一个,然后做......”但我了解到我的同事无法解开它,它与计算机完全一样。
    • 如果你喜欢这个拼写校正器,你应该学习haskell。集合上的函数映射是自然的github.com/timrobinson/spell-correct/blob/master/Correct.hs
    • 感谢链接,我一直在看 haskell,但我还没有时间真正进入它!
    【解决方案2】:

    re.match 只检查字符串的开头。

    使用 re.search()

    来自the docs

    Python 提供了两种不同的原语 基于常规的操作 表达式:匹配检查匹配 仅在字符串的开头, 而搜索检查匹配 字符串中的任何位置(这就是 Perl 默认会这样做)。

    【讨论】:

      【解决方案3】:

      将所有这些代码放入一个名为 pygrep 和 chmod +x pygrep 的文件中:

      #!/usr/bin/python
      
      import os
      import re
      import sys
      
      def file_match(fname, pat):
          try:
              f = open(fname, "rt")
          except IOError:
              return
          for i, line in enumerate(f):
              if pat.search(line):
                  print "%s: %i: %s" % (fname, i+1, line)
          f.close()
      
      
      def grep(dir_name, s_pat):
          pat = re.compile(s_pat)
          for dirpath, dirnames, filenames in os.walk(dir_name):
              for fname in filenames:
                  fullname = os.path.join(dirpath, fname)
                  file_match(fullname, pat)
      
      if len(sys.argv) != 3:
          u = "Usage: pygrep <dir_name> <pattern>\n"
          sys.stderr.write(u)
          sys.exit(1)
      
      grep(sys.argv[1], sys.argv[2])
      

      【讨论】:

      • +1 我很快就能够自定义它以使用更强大的更大选项集。
      【解决方案4】:
      import os, re
      
      def grep_r(regex, dir):
          for root, dirs, files in os.walk(dir):
              for f in files:
                  for m in grep(regex, os.path.join(root, f)):
                      yield m
      
      def grep(regex, filename):
          for i, line in enumerate(open(filename)):
              if re.match(regex, line): # or re.search depending on your default
                 yield "%s:%d: %s" % (os.path.basename(filename), i+1, line)
      

      【讨论】:

        【解决方案5】:

        为什么需要使用正则表达式?

        path=os.path.join("/dir1","dir2","dir3")
        pattern="test"
        for r,d,f in os.walk(path):
            for files in f:
                for n,line in enumerate(open( os.path.join(r,files) ) ):
                    if pattern in line:
                        print "%s found in line: %d of file: %s" %(pattern, n+1, files)
        

        【讨论】:

          猜你喜欢
          • 2011-05-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-21
          • 2016-06-29
          • 1970-01-01
          • 2021-11-15
          • 1970-01-01
          相关资源
          最近更新 更多