2009-12-07 5 views
4

Je voudrais implémenter la commande unix 'grep -r' dans une fonction python. Je sais à propos de commands.getstatusoutput(), mais pour l'instant je ne veux pas l'utiliser. Je suis venu avec ceci:grep -r en python

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 ] 

mais bien sûr ne pas utiliser une expression régulière, il vérifie juste si « str » est une sous-chaîne de « l ». donc j'ai essayé ce qui suit:

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) ] 

mais cela ne fonctionne pas, il ne me donne aucune correspondance même là où la première fonction a fait. Qu'est ce qui a changé? Je pourrais juste le diviser en un tas de boucles imbriquées, mais je suis plus intéressé à être succinct que lisible. Re.match ne vérifie que le début de la chaîne.

Répondre

5

utilisation re.search()

De the docs:

Python offre deux différentes opérations primitives basée sur réguliers expressions: chèques match pour un match seulement au début de la chaîne, pendant que la recherche vérifie une correspondance n'importe où dans la chaîne (c'est ce que fait Perl par défaut).

8

Vous pouvez search() au lieu de match() pour attraper les matchs au milieu des lignes, comme indiqué dans http://docs.python.org/library/re.html#matching-vs-searching

En outre, la structure et à l'intention de votre code est tout à fait caché. Je l'ai pythonisé.

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 
+0

oui, le mien est à peine lisible, depuis que je lis this article by Peter Norvig je continue à mettre les « i pour i dans some_generator 'déclarations dans mon code ... – aaronstacy

+0

Oh c'est naturel de vouloir utiliser les abstractions puissantes! J'avais l'habitude de faire de monstrueuses constructions multi-lignes de map() et reduce() avant que les compréhensions de listes ne se manifestent - j'ai vraiment aimé l'idée de "faire ceci, à tous" au lieu de "Ok le prochain et fais ... Ok, prenez le prochain et faites ... "Mais j'ai appris que mes collègues ne pouvaient pas le démêler, et c'est exactement la même chose à l'ordinateur. –

+0

Si vous aimez ce correcteur d'orthographe, vous devriez apprendre haskell. Les mappages de fonction sur les ensembles est un http://github.com/timrobinson/spell-correct/blob/master/Correct.hs naturel –

2
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) 
1

pourquoi avez-vous besoin d'utiliser regex?

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) 
3

Mettez tout ce code dans un fichier appelé pygrep et 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]) 
+0

+1 J'ai rapidement été capable de personnaliser ceci pour utiliser un plus grand ensemble d'options plus robuste. –