Regex 如何在Perl中提取匹配大括号之间的字符串?

Regex 如何在Perl中提取匹配大括号之间的字符串?,regex,perl,parsing,matching,braces,Regex,Perl,Parsing,Matching,Braces,我的输入文件如下: HEADER {ABC|*|DEF {GHI 0 1 0} {{Points {}}}} {ABC|*|DEF {GHI 0 2 0} {{Points {}}}} {ABC|*|XYZ:abc:def {GHI 0 22 0} {{Points {{F1 1.1} {F2 1.2} {F3 1.3} {F4 1.4}}}}} {ABC|*|XYZ:ghi:jkl {JKL 0 372 0} {{Points {}}}} {ABC|*|XYZ:mno:pqr {GH

我的输入文件如下:

HEADER 
{ABC|*|DEF {GHI 0 1 0} {{Points {}}}}

{ABC|*|DEF {GHI 0 2 0} {{Points {}}}}

{ABC|*|XYZ:abc:def {GHI 0 22 0} {{Points {{F1 1.1} {F2 1.2} {F3 1.3} {F4 1.4}}}}}

{ABC|*|XYZ:ghi:jkl {JKL 0 372 0} {{Points {}}}}

{ABC|*|XYZ:mno:pqr {GHI 0 34 0} {{Points {}}}}

{
    ABC|*|XYZ:abc:pqr {GHI 0 68 0}
        {{Points {{F1 11.11} {F2 12.10} {F3 14.11} {F4 16.23}}}}
        }
TRAILER
$array[0] = "{ABC|*|DEF {GHI 0 1 0} {{Points {}}}}"

$array[1] = "{ABC|*|DEF {GHI 0 2 0} {{Points {}}}}"

$array[2] = "{ABC|*|XYZ:abc:def {GHI 0 22 0} {{Points {{F1 1.1} {F2 1.2} {F3 1.3} {F4 1.4}}}}}"

..
..

$array[5] = "{
    ABC|*|XYZ:abc:pqr {GHI 0 68 0}
        {{Points {{F1 11.11} {F2 12.10} {F3 14.11} {F4 16.23}}}}
        }"
我想将文件解压缩到数组中,如下所示:

HEADER 
{ABC|*|DEF {GHI 0 1 0} {{Points {}}}}

{ABC|*|DEF {GHI 0 2 0} {{Points {}}}}

{ABC|*|XYZ:abc:def {GHI 0 22 0} {{Points {{F1 1.1} {F2 1.2} {F3 1.3} {F4 1.4}}}}}

{ABC|*|XYZ:ghi:jkl {JKL 0 372 0} {{Points {}}}}

{ABC|*|XYZ:mno:pqr {GHI 0 34 0} {{Points {}}}}

{
    ABC|*|XYZ:abc:pqr {GHI 0 68 0}
        {{Points {{F1 11.11} {F2 12.10} {F3 14.11} {F4 16.23}}}}
        }
TRAILER
$array[0] = "{ABC|*|DEF {GHI 0 1 0} {{Points {}}}}"

$array[1] = "{ABC|*|DEF {GHI 0 2 0} {{Points {}}}}"

$array[2] = "{ABC|*|XYZ:abc:def {GHI 0 22 0} {{Points {{F1 1.1} {F2 1.2} {F3 1.3} {F4 1.4}}}}}"

..
..

$array[5] = "{
    ABC|*|XYZ:abc:pqr {GHI 0 68 0}
        {{Points {{F1 11.11} {F2 12.10} {F3 14.11} {F4 16.23}}}}
        }"
这意味着,我需要将第一个开始的花括号与其结束的花括号匹配,并提取中间的字符串

我已经检查了下面的链接,但这不适用于我的问题。

我正在努力,但如果有人能用他们的专业知识帮助我,我真的会帮上忙

谢谢
Sri…

对于这种类型的解析,使用状态机比使用正则表达式要好得多。

我不认为这里要使用纯正则表达式(我想,使用正则表达式可能根本无法解析)

相反,构建一个小型解析器,类似于此处所示: (见shotgunefx(Parson)于2003年11月18日18:29 UTC的回答)


更新使用正则表达式似乎是可行的-我在中看到了匹配嵌套括号的引用(这在Google Books上可以找到,因此如果您没有这本书,可以在Google上搜索-请参阅第5章“匹配平衡括号集”一节)

正则表达式对于匹配大括号来说实际上非常糟糕。根据你想深入到什么程度,你可以写一个完整的语法(这比听起来容易得多!)。或者,如果您只想获得块,请搜索打开的“{”标记和关闭的“}”,然后计算在任何给定时间打开的块数。

使用

至少在现代版本的Perl中,正则表达式肯定可以做到这一点:

my @array = $str =~ /( \{ (?: [^{}]* | (?0) )* \} )/xg;

print join "\n" => @array;
正则表达式匹配一个大括号块,该块包含非大括号字符或递归(匹配嵌套大括号)

编辑:以上代码在Perl 5.10+中工作,对于早期版本,递归更为详细:

my $re; $re = qr/ \{ (?: [^{}]* | (??{$re}) )* \} /x;

my @array = $str =~ /$re/xg;

您始终可以计算大括号:

my $depth = 0;
my $out = "";
my @list=();
foreach my $fr (split(/([{}])/,$data)) {
    $out .= $fr;
    if($fr eq '{') {
        $depth ++;
    }
    elsif($fr eq '}') {
        $depth --;
        if($depth ==0) {
            $out =~ s/^.*?({.*}).*$/$1/s; # trim
            push @list, $out;
            $out = "";
        }
    }
}
print join("\n==================\n",@list);

这是一种老式的、朴素的Perl风格(可能也很难看)。

我支持ysth关于使用该模块的建议。几句话就可以让你上路了

use strict;
use warnings;
use Text::Balanced qw/extract_multiple extract_bracketed/;

my $file;
open my $fileHandle, '<', 'file.txt';

{ 
  local $/ = undef; # or use File::Slurp
  $file = <$fileHandle>;
}

close $fileHandle;

my @array = extract_multiple(
                               $file,
                               [ sub{extract_bracketed($_[0], '{}')},],
                               undef,
                               1
                            );

print $_,"\n" foreach @array;

尝试了这个,但是我得到了在正则表达式中无法识别的错误序列(?0…);以@Srilesh=>我发布的代码需要perl 5.10+为标记,我编辑了我的答案,其中包含了一个可以在较旧的perl中使用的版本。由@ysth、@Zaid、@leonbloy提供的解决方案对我来说很好,但@eric的解决方案性能非常好。我在一个10MB的文件上应用递归,结果与其他文件相比非常快。选择您的答案是这里的最佳解决方案。非常感谢。根据ysth的建议,我使用了Text::Balanced,但我只得到了第一个匹配项。谢谢你在这里帮助我,我也需要使用extract_multiple sub。谢谢…谢谢你,这是最好的解决方案@斯里莱什:如果你最喜欢这个答案,请点击答案左边的勾选框。谢谢zig,你的回答很有帮助。