查找在前面的注释中也提到了名称的 C 函数定义
Find C function definitions where the name is also mentioned in the preceding comment
我有一个C文件。使用 C 风格的注释集 /* */ 后跟为每个注释定义的变量。变量名也在注释中。一些注释包含它们不适用的变量名称(参见下面示例中的第 3 条注释)
以下是格式示例:
/* Object: function1: Does some really cool things and then it ends */
const function1 = someValue;
/* Object: function2: Does more really cool things and then it ends */
const function2 = someValue2;
/* Object: function3: Does even more really cool things
just like function2, does but continues over to the next line for a multiline comment */
const function3 = someValue3;
/* Object: function4: Does all kinds of cool things
and needs function1 in order to set a value correctly */
const function4 = someValue4;
/* Object: function5: Does some other cool things
and needs function2[with another variable] to do some things */
const function5 = someBValue5;
我只想将变量名与这样的结果相匹配:
功能1
功能2
函数3
功能4
函数 5
我已经在 https://regexr.com/ 上玩这个几个小时了,但我无法得到这个。
这是我尝试过的:
有了这个 post 它使用了负面的回顾。我不能使用负后视,因为此正则表达式正在 Windows 10 机器上的 Perl 5.32.1 中使用。
这是我能想到的最好的:
(\bfunction[\w]+\b[^:,])
它排除了与 : 或 匹配的行,但不排除包含在 /* */ 中的重复项。但是除了使用我无法使用的负面回顾之外,我一直无法弄清楚。
最终,我认为最好的解决方案是排除 /* */ 之间的所有内容,只搜索评论中未包含的内容。但它需要支持排除多行评论内容并且不能使用负面回顾。
测试第 1 轮
这不是我的问题的完整答案,因为它没有省略函数名前面的 const & space。 function1、function 2 等只是通用函数名称。它们将是字母数字,所以相信 function[\w]+ 仍然提供函数名称的最佳捕获。
尝试使用 const
作为过滤器:
"const (\bfunction[\w]+\b[^:,])"
它不允许其他邻居,为您提供函数名称的唯一值。
为了获取您的组,您需要引用
,您将只获取函数名称。
我对这个问题的看法:从它的定义中找到一个函数名称(后跟 =
)在评论之外,但在提到它的评论之后(后跟 :
)。
这是一个简单的 step-by-step state-full 方法:检测我们是否在评论中,以及我们是否找到 /(function[0-9]+):/
,并设置合适的标志;然后在评论和更新标志后寻找相同的功能。
use warnings;
use strict;
use feature 'say';
my $file = shift // die "Usage: [=10=] filename\n";
open my $fh, '<', $file or die $!;
my (@func_names, $inside_comment, $func_name);
while (<$fh>) {
chomp;
# Are we inside a comment? Look for function[0-9]+:
if (m{/\*}) { #/ fix syntax hilite
$inside_comment = 1 if not m{\*/}; #/ starts multiline comment?
if (/(function[0-9]+):/) {
$func_name = ;
}
}
elsif (m{\*/}) { #/ closing line for multiline comment
$inside_comment = 0;
if (not $func_name and /(function[0-9]+):/) { #/
$func_name = ;
}
}
elsif ($inside_comment and not $func_name) {
if (/(function[0-9]+):/) {
$func_name = ;
}
}
# Check for name outside (after) a comment where it was found
elsif (not $inside_comment and $func_name) {
if (/(function[0-9]+)\s+=/) {
say "Found our definition: ";
push @func_names, ;
$func_name = '';
}
}
}
say for @func_names;
使用提供的样本可以按预期打印。
缺点:每行都用正则表达式测试两次。对于像源代码这样的小文件,人们永远不会注意到,但这并不好。
可能有(edge?)情况没有涵盖,†请测试改进。
另一种选择。将整个文件读入一个字符串,并通过注释单步执行,在每个字符串后检查函数名;或者,解析它以获得评论 + function-definition。两者都使用 \G
+ /g
.
use warnings;
use strict;
use feature 'say';
die "Usage [=11=] filename\n" if not @ARGV;
my $cont = do { local $/; <> };
# Pattern inside a C-style comment, possibly multiline (NOTE: not general)
my $re_cc = qr{/\* .*? (function[0-9]+): .*? \*/}sx;
my @func_names;
while ($cont =~ /$re_cc\s*/gc) {
my $func_name = ;
if ( $cont =~ /\G .*? (function[0-9]+)\s*=/x and $func_name eq ) {
push @func_names, ;
}
}
了解锚点 \G
及其与修饰符 /g
in perlop. Some other resources are this page and this post 的结合使用(还有更多内容)。
这做了一些假设,也许稍微安全一点的版本是
use warnings;
use strict;
use feature 'say';
die "Usage [=12=] filename\n" if not @ARGV;
my $cont = do { local $/; <> };
# Pattern inside a C-style comment, possibly multiline (NOTE: not general)
my $re_cc = qr{/\* .*? (function[0-9]+): .*? \*/}sx;
my (@func_names, $func_name);
while (1) {
if ($cont =~ /\G $re_cc \s*/gcx) {
$func_name = ;
}
elsif ($cont =~ /\G (function[0-9]+)\s* = .*?\n\s*/gcx
and $func_name eq ) {
#say "Found function definition for: (at pos=", pos $cont, ")";
push @func_names, ;
$func_name = '';
}
elsif ($cont =~ /\G \S+ \s*/gcx) { } # other, skip
else { last }
}
say for @func_names;
这些都可以正确处理提供的文件,但对于更一般的情况肯定可以改进。‡
请记住,一般和正确识别 C-style 评论可能非常棘手。参见 this perldoc FAQ
† 一:如果评论不是后跟定义我们的标志可能会保持错误状态
‡ 虽然关于改进的说明是关于其一般操作,但这里是相关的正则表达式注释。
$re_cc
模式使用 /s
修饰符,以便 .
也匹配换行符,因为它必须是 .*
才能跨多行匹配。但是,这种修饰符是全局设置的,它适用于使用此模式的正则表达式的 rest!嗯,这可能不是故意的。
在这种情况下,我看不出这有什么关系,但万一有办法设置 embedded (pattern-match) modifier,它仅适用于模式
/(?s)pattern(?-s)/
或者,如果模式在其组内自然起作用,则修改器将被丢弃在它之外,因此我们不需要使用 (?-s)
取消它
/((?s)pattern)/
我有一个C文件。使用 C 风格的注释集 /* */ 后跟为每个注释定义的变量。变量名也在注释中。一些注释包含它们不适用的变量名称(参见下面示例中的第 3 条注释)
以下是格式示例:
/* Object: function1: Does some really cool things and then it ends */
const function1 = someValue;
/* Object: function2: Does more really cool things and then it ends */
const function2 = someValue2;
/* Object: function3: Does even more really cool things
just like function2, does but continues over to the next line for a multiline comment */
const function3 = someValue3;
/* Object: function4: Does all kinds of cool things
and needs function1 in order to set a value correctly */
const function4 = someValue4;
/* Object: function5: Does some other cool things
and needs function2[with another variable] to do some things */
const function5 = someBValue5;
我只想将变量名与这样的结果相匹配: 功能1 功能2 函数3 功能4 函数 5
我已经在 https://regexr.com/ 上玩这个几个小时了,但我无法得到这个。
这是我尝试过的:
这是我能想到的最好的:
(\bfunction[\w]+\b[^:,])
它排除了与 : 或 匹配的行,但不排除包含在 /* */ 中的重复项。但是除了使用我无法使用的负面回顾之外,我一直无法弄清楚。
最终,我认为最好的解决方案是排除 /* */ 之间的所有内容,只搜索评论中未包含的内容。但它需要支持排除多行评论内容并且不能使用负面回顾。
测试第 1 轮
这不是我的问题的完整答案,因为它没有省略函数名前面的 const & space。 function1、function 2 等只是通用函数名称。它们将是字母数字,所以相信 function[\w]+ 仍然提供函数名称的最佳捕获。
尝试使用 const
作为过滤器:
"const (\bfunction[\w]+\b[^:,])"
它不允许其他邻居,为您提供函数名称的唯一值。
为了获取您的组,您需要引用 ,您将只获取函数名称。
我对这个问题的看法:从它的定义中找到一个函数名称(后跟 =
)在评论之外,但在提到它的评论之后(后跟 :
)。
这是一个简单的 step-by-step state-full 方法:检测我们是否在评论中,以及我们是否找到 /(function[0-9]+):/
,并设置合适的标志;然后在评论和更新标志后寻找相同的功能。
use warnings;
use strict;
use feature 'say';
my $file = shift // die "Usage: [=10=] filename\n";
open my $fh, '<', $file or die $!;
my (@func_names, $inside_comment, $func_name);
while (<$fh>) {
chomp;
# Are we inside a comment? Look for function[0-9]+:
if (m{/\*}) { #/ fix syntax hilite
$inside_comment = 1 if not m{\*/}; #/ starts multiline comment?
if (/(function[0-9]+):/) {
$func_name = ;
}
}
elsif (m{\*/}) { #/ closing line for multiline comment
$inside_comment = 0;
if (not $func_name and /(function[0-9]+):/) { #/
$func_name = ;
}
}
elsif ($inside_comment and not $func_name) {
if (/(function[0-9]+):/) {
$func_name = ;
}
}
# Check for name outside (after) a comment where it was found
elsif (not $inside_comment and $func_name) {
if (/(function[0-9]+)\s+=/) {
say "Found our definition: ";
push @func_names, ;
$func_name = '';
}
}
}
say for @func_names;
使用提供的样本可以按预期打印。 缺点:每行都用正则表达式测试两次。对于像源代码这样的小文件,人们永远不会注意到,但这并不好。 可能有(edge?)情况没有涵盖,†请测试改进。
另一种选择。将整个文件读入一个字符串,并通过注释单步执行,在每个字符串后检查函数名;或者,解析它以获得评论 + function-definition。两者都使用 \G
+ /g
.
use warnings;
use strict;
use feature 'say';
die "Usage [=11=] filename\n" if not @ARGV;
my $cont = do { local $/; <> };
# Pattern inside a C-style comment, possibly multiline (NOTE: not general)
my $re_cc = qr{/\* .*? (function[0-9]+): .*? \*/}sx;
my @func_names;
while ($cont =~ /$re_cc\s*/gc) {
my $func_name = ;
if ( $cont =~ /\G .*? (function[0-9]+)\s*=/x and $func_name eq ) {
push @func_names, ;
}
}
了解锚点 \G
及其与修饰符 /g
in perlop. Some other resources are this page and this post 的结合使用(还有更多内容)。
这做了一些假设,也许稍微安全一点的版本是
use warnings;
use strict;
use feature 'say';
die "Usage [=12=] filename\n" if not @ARGV;
my $cont = do { local $/; <> };
# Pattern inside a C-style comment, possibly multiline (NOTE: not general)
my $re_cc = qr{/\* .*? (function[0-9]+): .*? \*/}sx;
my (@func_names, $func_name);
while (1) {
if ($cont =~ /\G $re_cc \s*/gcx) {
$func_name = ;
}
elsif ($cont =~ /\G (function[0-9]+)\s* = .*?\n\s*/gcx
and $func_name eq ) {
#say "Found function definition for: (at pos=", pos $cont, ")";
push @func_names, ;
$func_name = '';
}
elsif ($cont =~ /\G \S+ \s*/gcx) { } # other, skip
else { last }
}
say for @func_names;
这些都可以正确处理提供的文件,但对于更一般的情况肯定可以改进。‡
请记住,一般和正确识别 C-style 评论可能非常棘手。参见 this perldoc FAQ
† 一:如果评论不是后跟定义我们的标志可能会保持错误状态
‡ 虽然关于改进的说明是关于其一般操作,但这里是相关的正则表达式注释。
$re_cc
模式使用 /s
修饰符,以便 .
也匹配换行符,因为它必须是 .*
才能跨多行匹配。但是,这种修饰符是全局设置的,它适用于使用此模式的正则表达式的 rest!嗯,这可能不是故意的。
在这种情况下,我看不出这有什么关系,但万一有办法设置 embedded (pattern-match) modifier,它仅适用于模式
/(?s)pattern(?-s)/
或者,如果模式在其组内自然起作用,则修改器将被丢弃在它之外,因此我们不需要使用 (?-s)
/((?s)pattern)/