如何从Perl中的另一个文件中的一个文件中找到字符串?

时间:2009-05-16 15:25:51

标签: perl

下面的脚本在文本文件中获取函数名称并在a上进行扫描 包含多个c,h文件的文件夹。它一个接一个地打开这些文件 读取每一行。如果在文件的任何部分中找到匹配项,则会打印出 行号和包含匹配的行。

除非比较不正常,否则一切正常。我会非常感谢能解决我问题的人。

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

3 个答案:

答案 0 :(得分:2)

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

你错过了一个结束括号。应该是:

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

这也可能比这四种陈述更容易。但是,把我的头脑包裹起来还有点早。你想在“function foo(){”中匹配“foo”吗?如果是这样,你可以使用像/ \ s +([^]] +)/。

这样的正则表达式

当您说$func_name =~$func_name_input时,您将$ func_name_input中的所有字符视为特殊的正则表达式字符。如果这不是您的意思,您可以使用quotemeta(perldoc -f quotemeta):$func_name =~quotemeta($func_name_input)$func_name =~ qr/\Q$func_name_input\E/


使用strictures(以及语法高亮显示编辑器)可以更轻松地进行调试。另请注意,如果您没有在其他文件中使用这些变量,“我们的”不执行任何“我的”不会对文件范围的变量执行任何操作。

答案 1 :(得分:1)

find + xargs + grep可以达到你想要的90%。

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

ack更容易。

ack --type=cc your_pattern

只需从您的文件中获取您的模式列表,然后“或”将它们放在一起。

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

这样做的好处是只搜索一次文件,而不是为你正在搜索的每个模式搜索一次。

答案 2 :(得分:1)

我仍然认为你应该使用ack,但你的代码需要一些严肃的爱。

这是您的程序的改进版本。它现在需要在命令行上搜索和模式的目录,而不是要求(和用户写入)文件。它使用File :: Find搜索目录下的所有文件,而不仅仅是目录中的文件。它通过将所有模式连接成正则表达式一次完成此操作。它使用正则表达式而不是index()和substr()以及reverse()和哦上帝。它只使用内置的文件句柄而不是FileHandle模块并检查eof()。一切都被声明为词汇(我的)而不是全局(我们的)。严格和警告正在进行,以便于调试。

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