关于 perl:如何递归提取两个字符之间的字符串?

How can I extract a string between two characters + do it RECURSIVELY?

我有一个字符串:

1
123 + FOO1[ccc + e_FOO1 + ddd + FOO2[b_FOO2]] = 123

现在,我需要检查 FOO1 是否与 e_ 一起显示。也就是说,不可能有这样的情况:

1
123 + FOO1[ccc + e_FOK1 ...]

我的简单问题是如何告诉 Perl 捕捉 FOO1 单词?

我想在 2 个字符之间进行搜索:"""["

然后检查是否在"[..]"之间的" e_"之后写入正确。例如

我怎样才能递归呢?


您需要为您的迷你语言编写解析器:请参阅 Parse::RecDescent。计算器演示将是一个很好的起点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/perl

use strict;
use warnings;

my ($expr) = @ARGV;

my @tokens = split //, $expr;

my ($word, $inside) = (q{}, 0);

for my $token (@tokens) {
    $token =~ /\\A\\w\\z/ and do { $word .= $token; next };

    if ( $inside ) {
        if ( $word =~ /FOO1/ ) {
            $word eq 'e_FOO1'
                or die"No FOO1 w/o e_ prefix allowed!\
"

        }
    }
    else {
        $word !~ /FOO1/
            or die"No FOO1 allowed!\
"
;
    }

    $token eq '[' and ++$inside;
    $token eq ']' and --$inside;
    $word = '';
}

1
C:\\Temp> t.pl"123 + MOO1[ccc + e_FOO1 + ddd + FOO2[b_FOO2]] = 123"
1
2
C:\\Temp> t.pl"123 + FOO1[ccc + e_FOO1 + ddd + FOO2[b_FOO2]] = 123"
No FOO1 allowed!
1
2
C:\\Temp> t.pl"123 + MOO1[ccc + FOO1 + ddd + FOO2[b_FOO2]] = 123"
No FOO1 w/o e_ prefix allowed!

另请参阅常见问题解答 我可以使用 Perl 正则表达式来匹配平衡文本吗?


根据您的一些评论,我将假设您的问题是"在'['和']'括号之间,确保任何'e_'符号都是'e_FOO'而不是其他东西......

(编辑:好的,看起来你需要"FOO"关键字也出现在方括号之前。我会相应地修改正则表达式。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if ($line =~ /
              ([A-Z]+)  # match a keyword in all caps, and save it for later
                        # (we can retrieve it with \\1 or $1)
              \\[        # match the first [
                [\\]]*   # some number of any character that isn't ]
                e_      # a ha, here's our e_
                \\1      # and here's our keyword that we matched earlier
                [\\]]*   # some more of any character that isn't ]
              \\]        # here's our closing ]
             /x)
{
     say"Good data";
}
else
{
     say"Bad data";
}

但是,请开始阅读 perldoc perlre 中的一些教程。


既然你说"我需要确认 FOO1 跟在括号内的"e_"字符串后面",你只需要检查 e_FOO1,对吗?不需要太复杂的正则表达式。

1
2
3
4
5
6
7
8
my $str="123 + FOO1[ccc + e_FOO1 + ddd + FOO2[b_FOO2]] = 123";
my $s = index($str,"[");
my $e = index($str,"]");
my $f = index($str,"e_FOO1");
if ( $f >=$s and $f <= $e ){
    print"found \
"
;
}


如果您的情况比您描述的更复杂,则此代码将不起作用(例如,它无法确保您的左右括号相互平衡)。但是,代码确实说明了如何使用反向引用(请参阅下面的 \\1),这可能会让您走上正轨。

1
2
3
4
5
6
7
8
9
10
use strict;
use warnings;

while (<DATA>){
    warn"Bad line: $_" unless / (\\w+) \\[ .* e_\\1 .* \\] /x;
}

__DATA__
123 + FOO1[ccc + e_FOO1 + ddd + FOO2[b_FOO2]] = 123
123 + FOO1[ccc + e_FOOx + ddd + FOO2[b_FOO2]] = 123