我想要检索文本文件中的一个函数(仅定义函数而不是调用函数)(计数)
文本文件{function.txt}位于
之下#include<main.h>
#include<mncl.h>
int reg23;
int refid23;
int64 AccounntBalance(char *reg12,char *refid,char **id){ //dis is function1
ref();
if(id>100)
{
do(&ref);
}
} //dis is end of fucntion1
void AccountRetrivalForm(char **regid,char **balance,char **id) //dis is function2
{
doref();
int register;
if(refid!=null)
{
dolog();
}
} //dis is end of function2
现在我的逻辑程序是:
#!C:/strawberry/perl
use strict;
use warnings;
my $filename = 'function_perl.txt';
my $function_count = 0;
open(FILENAME,$filename);
my @arr = join("\n",<FILENAME>);
foreach my $string(@arr)
{
if($string =~/(?:int64|void|boolean)\s?(.*?)\(.*?\)\s*\{/)
{
print "HAI";
$function_count++;
print '$function_count';
}
}
这里Function_count是1.它永远不会增加第二场比赛....请帮我用相同的代码...我试了这么久。我觉得很难解决这个问题。
答案 0 :(得分:4)
也许这个例子会有所帮助:
use strict;
use warnings;
my $n;
# Supply the input file name as a command-line argument.
# Perl will open the file and process it line by line.
# No need to hard-code the file name in the program, which
# means the script could be reused.
while (my $line = <>){
# The regex is applied against $line.
# It will return the items captured by parentheses.
# The /x option causes Perl to ignore whitespace
# in our definition of the regex -- for readability.
my ($type, $func, $args) = $line =~ /^
( int64|void|boolean ) \s+
( \w+ ) \s*
\( (.+?) \)
/x;
# Skip the line if our regex failed.
next unless defined $type;
# Keep track of N of functions, print output, whatever...
$n ++;
print $_, "\n" for '', $type, $func, $args;
}
print "\nN of functions = $n\n";
答案 1 :(得分:3)
你的正则表达式是不正确的。
^([int64/void/boolean)]/(.*)/\(/\{//\n
你可能意味着之类的东西:
/^(int64|void|boolean)\s+(\w+)\s*\(.*?\)\s*\{/
即int64
,void
或boolean
中的一个,一些空格,一个标识符,可选空格,一个左括号,一些内容,一个右括号,一些可选的空格(可能是换行符),以及一个大括号。
答案 2 :(得分:3)
我想说你浏览文件的方式很不寻常。通常你会使用像
这样的东西open my $handle, '<', $filename;
while (<$handle>) {
if (/^(void|boolean|int64).../) {
do something;
}
}
close $handle;
代码的作用是打开文件并一次读取一行。这与获取整个数组,连接它并迭代其元素一样。
使用Perl的一个不相关的重要提示:在脚本开头之后包含三行:
#!/usr/bin/perl
use strict;
use warnings;
use autodie qw(:all);
如果您尝试在串联中使用某些未分配的变量以及其他内容,则会发出警告。 strict包强制您使用my
关键字声明变量。这听起来有点麻烦,但它也可以防止你因为错误输入变量而遇到问题。使用严格的Perl解释器会警告你一个未声明的变量。 autodie pragma检查系统调用失败,例如open
。
您正在使用的正则表达式是错误的。你必须要知道Perl中的regexp用斜杠括起来,所以/\s+\w*.*/
是一个有效的正则表达式。你正在使用正则表达式中的斜杠,它会过早地关闭表达式。如果你必须在文本中再次匹配斜杠,则必须使用反斜杠转义它们或者完全使用不同的分隔符。
@filecontent
与@file_content
。这是use strict;
警告你的完美场所。
答案 3 :(得分:3)
正则表达式不是解析器。如果可以,最好使用解析器。
一种简单的方法是依靠ctags中的解析器:
#! /usr/bin/perl
use warnings;
use strict;
sub usage { "Usage: $0 source-file\n" }
die usage unless @ARGV == 1;
open my $ctags, "-|", "ctags", "-f", "-", @ARGV
or die "$0: failed to start ctags\n";
while (<$ctags>) {
chomp;
my @fields = split /\t/;
next unless $fields[-1] eq "f";
print $fields[0], "\n";
}
示例运行:
$ ./getfuncs prog.cc AccounntBalance AccountRetrivalForm
另一种方法涉及g ++的选项-fdump-translation-unit
,它导致它转储解析树的表示,你可以通过它来挖掘它,如下例所示。
我们从通常的前端问题开始:
#! /usr/bin/perl
use warnings;
use strict;
处理需要源文件的名称和任何必要的编译器标志。
sub usage { "Usage: $0 source-file [ cflags ]\n" }
翻译单元转储具有简单的格式:
@1 namespace_decl name: @2 srcp: :0 dcls: @3 @2 identifier_node strg: :: lngt: 2 @3 function_decl name: @4 mngl: @5 type: @6 srcp: prog.c:12 chan: @7 args: @8 link: extern @4 identifier_node strg: AccountRetrivalForm lngt: 19
如您所见,每条记录都以标识符开头,后跟一个类型,然后是一个或多个属性。正则表达式和一些哈希处理就足以给我们一棵树来检查。
sub read_tu {
my($path) = @_;
my %node;
open my $fh, "<", $path or die "$0: open $path: $!";
my $tu = do { local $/; <$fh> };
my $attrname = qr/\b\w+(?=:)/;
my $attr =
qr/($attrname): \s+ (.+?) # name-value
(?= \s+ $attrname | \s*$ ) # terminated by whitespace or EOL
/xm;
my $fullnode =
qr/^(@\d+) \s+ (\S+) \s+ # id and type
((?: $attr \s*)+) # one or more attributes
\s*$ # consume entire line
/xm;
while ($tu =~ /$fullnode/g) {
my($id,$type,$attrs) = ($1,$2,$3);
$node{$id} = { TYPE => $type };
while ($attrs =~ /$attr \s*/gx) {
if (exists $node{$id}{$1}) {
$node{$id}{$1} = [ $node{$id}{$1} ] unless ref $node{$id}{$1};
push @{ $node{$id}{$1} } => $2;
}
else {
$node{$id}{$1} = $2;
}
}
}
wantarray ? %node : \%node;
}
在主程序中,我们将代码提供给g ++
die usage unless @ARGV >= 1;
my($src,@cflags) = @ARGV;
system("g++", "-c", "-fdump-translation-unit", @cflags, $src) == 0
or die "$0: g++ failed\n";
my @tu = glob "$src.*.tu";
unless (@tu == 1) {
die "$0: expected one $src.*.tu file, but found",
@tu ? ("\n", map(" - $_\n", @tu))
: " none\n";
}
假设一切顺利,我们就会挑出指定源文件中给出的函数定义。
my $node = read_tu @tu;
sub isfunc {
my($n) = @_;
$n->{TYPE} eq "function_decl"
&&
index($n->{srcp}, "$src:") == 0;
}
sub nameof {
my($n) = @_;
return "<undefined>" unless exists $n->{name};
$n->{name} =~ /^@/
? $node->{ $n->{name} }{strg}
: $n->{name};
}
print "$_\n" for sort
map nameof($_),
grep isfunc($_),
values %$node;
示例运行:
$ ./getfuncs prog.cc -I. AccounntBalance AccountRetrivalForm
答案 4 :(得分:1)
这样可以解决问题:
#!/usr/bin/env perl
use strict;
use warnings;
use autodie qw(:all);
my $function_count = 0;
open my $input, '<', 'function.txt';
while (defined(my $line = <$input>)) {
chomp($line);
if (my ($func) = $line =~ /^(?:int64|void|boolean)\s?(.*?)\(/) {
print qq{Found function "$func"\n};
$function_count++;
}
}
close $input;
print "$function_count\n";
考虑到函数调用的修改后的答案:
#!/usr/bin/env perl
use strict;
use warnings;
use autodie qw(:all);
my $document;
{
local $/ = undef;
open my $input, '<', 'function.txt';
$document = <$input>;
chomp $document;
close $input;
}
my $function_count = 0;
while (my ($func) = $document =~ /(?:int64|void|boolean)\s?(.*?)\(.*?\)\s*\{/gs)) {
print qq{Found function "$func"\n};
$function_count++;
}
print "$function_count\n";