2009-05-16 7 views
0

Le script ci-dessous prend les noms de fonctions dans un fichier texte et numérise un dossier contenant plusieurs fichiers c, h. Il ouvre ces fichiers un par un et lit chaque ligne. Si la correspondance est trouvée dans une partie quelconque des fichiers, elle imprime le numéro de ligne et la ligne qui contient la correspondance.Comment puis-je trouver les chaînes d'un fichier dans un autre fichier en Perl?

Tout fonctionne correctement, sauf que la comparaison ne fonctionne pas correctement. Je serais très reconnaissant à quiconque résout mon problème.

#program starts: 

    use FileHandle; 
    print "ENTER THE PATH OF THE FILE THAT CONTAINS THE FUNCTIONS THAT YOU WANT TO  
    SEARCH: ";#getting the input file 
    our $input_path = <STDIN>; 
    $input_path =~ s/\s+$//; 
    open(FILE_R1,'<',"$input_path") || die "File open failed!"; 
    print "ENTER THE PATH OF THE FUNCTION MODEL: ";#getting the folder path that 
               #contains multiple .c,.h files 
    our $model_path = <STDIN>; 
    $model_path =~ s/\s+$//; 
    our $last_dir = uc(substr ($model_path,rindex($model_path, "\\") +1)); 
    our $output = $last_dir."_FUNC_file_names"; 

    while(our $func_name_input = <FILE_R1>)#$func_name_input is the function name 
              #that is taken as the input 
    { 
    $func_name_input=reverse($func_name_input); 
    $func_name_input=substr($func_name_input,rindex($func_name_input,"\("+1); 
    $func_name_input=reverse($func_name_input); 
    $func_name_input=substr($func_name_input,index($func_name_input," ")+1); 

    #above 4 lines are func_name_input is choped and only part of the function 
    #name is taken. 

    opendir FUNC_MODEL,$model_path; 
    while (our $file = readdir(FUNC_MODEL)) 
    { 
     next if($file !~ m/\.(c|h)/i); 
     find_func($file);  
    } 
    close(FUNC_MODEL); 
    } 


    sub find_func() 
    { 
    my $fh1 = FileHandle->new("$model_path//$file") or die "ERROR: $!"; 

    while (!$fh1->eof()) 
    { 
     my $func_name = $fh1->getline(); #getting the line 

     **if($func_name =~$func_name_input)**#problem here it does not take the 
               #match 
     { 
      next if($func_name=~m/^\s+/); 
      print "$.,$func_name\n"; 
     } 
     } 
    } 
+1

Qu'est-ce que tout ce que reverse/substr/rindex fait à $ func_name_input? – Schwern

Répondre

2
$func_name_input=substr($func_name_input,rindex($func_name_input,"\("+1); 

vous manque une parenthèse fin. Devrait être:

$func_name_input=substr($func_name_input,rindex($func_name_input,"\(")+1); 

Il existe probablement un moyen plus simple que ces quatre instructions. Mais il est un peu tôt pour envelopper ma tête. Voulez-vous faire correspondre "foo" dans "function foo() {"? Si oui, vous pouvez utiliser une regex comme/\ s + ([^)] +) /.


Quand vous dites $func_name =~$func_name_input, vous traitez tous les caractères func_name_input de $ sous forme de caractères spéciaux regex. Si ce n'est pas ce que vous voulez faire, vous pouvez utiliser quotemeta (perldoc -f quotemeta): $func_name =~quotemeta($func_name_input) ou $func_name =~ qr/\Q$func_name_input\E/.


Debugging sera plus facile avec strictures (et un éditeur syntaxe hilighting). Notez également que, si vous n'utilisez pas ces variables dans d'autres fichiers, "notre" ne fait rien que "mon" ne ferait pour les variables de portée de fichier.

1

trouver + xargs + grep fait 90% de ce que vous voulez.

find . -name '*.[c|h]' | xargs grep -n your_pattern 

ack il fait encore plus facile. Il suffit de prendre votre liste de modèles de votre fichier et "ou" les ensemble.

ack --type=cc 'foo|bar|baz' 

Ceci a l'avantage de ne rechercher les fichiers une fois, et non une fois pour chaque modèle recherchée que vous faites.

1

Je pense toujours que vous devriez juste utiliser ACK, mais votre code a besoin d'un amour sérieux.

Voici une version améliorée de votre programme. Il prend maintenant le répertoire pour rechercher et des modèles sur la ligne de commande au lieu d'avoir à demander (et écrire l'utilisateur) des fichiers. Il recherche tous les fichiers dans le répertoire, pas seulement ceux du répertoire, en utilisant File :: Find. Il le fait en une passe en concaténant tous les motifs en expressions régulières. Il utilise regexes au lieu de index() et substr() et reverse() et oh mon dieu. Il utilise simplement des handles de fichiers intégrés plutôt que le module FileHandle et vérifie eof(). Tout est déclaré lexical (my) au lieu de global (notre). Strict et les avertissements sont sur pour faciliter le débogage.

#!/usr/bin/perl 

use strict; 
use warnings; 
use File::Find; 

die "Usage: search_directory function ...\n" unless @ARGV >= 2; 

my $Search_Dir = shift; 
my $Pattern = build_pattern(@ARGV); 

find(
    { 
     wanted => sub { 
      return unless $File::Find::name =~ m/\.(c|h)$/i; 
      find_func($File::Find::name, $pattern); 
     }, 
     no_chdir => 1, 
    }, 
    $Search_Dir 
); 


# Join all the function names into one pattern 
sub build_pattern { 
    my @patterns; 
    for my $name (@_) { 
     # Turn foo() into foo. This replaces all that reverse() and rindex() 
     # and substr() stuff. 
     $name =~ s{\(.*}{}; 

     # Use \Q to protect against regex metacharacters in the input 
     push @patterns, qr{\Q$name\E}; 
    } 

    # Join them up into one pattern. 
    return join "|", @patterns; 
} 


sub find_func { 
    my($file, $pattern) = @_; 

    open(my $fh, "<", $file) or die "Can't open $file: $!"; 

    while (my $line = <$fh>) { 
     # XXX not all functions are unindented, but your choice 
     next if $line =~ m/^\s+/; 

     print "$file:$.: $line" if $line =~ $pattern; 
    } 
} 
+0

Salut merci pour votre réponse .... mais je suis novice à perl .. pouvez-vous me xplain en détail ... quand je cours ur code il me donne erreur ... merci encore beaucoup ...mon intension est que j'ai la liste des noms de fonctions dans un fichier texte et je veux rechercher ces noms de fonctions dans tous les fichiers c et h fichiers qui contiennent dans un dossier et afficher la ligne non et la ligne entière wer il est utilisé ... par exemple ... dans le fichier texte, il peut être lik foo() ou void foo (abc) ou foo seul aussi ... donc je dois prendre foo seul et chercher l'utilisation .. et aussi la ligne où il est appelé ... merci beaucoup si vous résolvez mon problème .. – User1611

+0

Bon code propre, mais vous avez une erreur. File :: Find modifie le répertoire de travail au fur et à mesure. Si vous modifiez l'appel à find_func (ligne 15) pour être: findunc ($ _, $ Pattern); alors le code fonctionne. – daotoad

+0

@daotoad Ahh, ça a marché pour moi parce que je le nourrissais toujours d'un chemin absolu. Utiliser $ _ n'est pas tout à fait correct car il ne peut pas imprimer le chemin complet du fichier correspondant. Au lieu de cela, je vais utiliser no_chdir et $ File :: Find :: name. Merci. – Schwern

Questions connexes