How can I find lines from one file in another file in Perl?

Below is a list of script that contains function names in a text file and scans that contains multiple files c, h. It opens these files one by one and reads each line. If a match is found anywhere in the files, it prints the line number and the line containing the match.

Everything works fine, except the comparison doesn't work properly. I would be very grateful to someone who solves my problem.

  #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";
         }
      }
   }

      

0


a source to share


3 answers


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

      

You are missing the ending parenthesis. Should be:

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

      

This is probably easier than these four statements. But it's a little early to wrap everything around me. Do you want to match "foo" into "function foo () {"? If so, you can use a regular expression like / \ s + ([^)] +) /.




When you say $func_name =~$func_name_input

, you treat all characters in $ func_name_input as special regex characters. If that's not what you want to do, you can use quotemeta (perldoc -f quotemeta): $func_name =~quotemeta($func_name_input)

or $func_name =~ qr/\Q$func_name_input\E/

.


Debugging will be easier with strictures (and the syntax-hilighting editor). Also note that if you don't use these variables in other files, "our" does nothing, "mine" will not use scoped variables.

+2


a source


find + xargs + grep does 90% of what you want.

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

      

ack makes this even easier.

ack --type=cc your_pattern

      



Just take your list of templates from your file and "or" them together.

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

      

This is only useful for finding files once, not once for finding each pattern as you do.

+1


a source


I still think you should just use ack, but your code needed some serious love.

Here is an improved version of your program. It now looks for a directory to look for and templates on the command line, rather than asking for files (and user files). It searches for all files in a directory, not just files in a directory, using File :: Find. It does this in one go, concatenating all the patterns into regular expressions. It uses regular expressions instead of index () and substr () and reverse () and oh god. It just uses the built-in file descriptors, not the FileHandle module, and checks for the presence of eof (). Everything is declared as lexical (mine), not global (our). Strict and warnings are included for easier debugging.

#!/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;
    }
}

      

+1


a source







All Articles