12

我的输入文件如下:

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

这意味着,我需要将第一个左大括号与其右大括号匹配,并提取其间的字符串。

我已经检查了以下链接,但这不适用于我的问题。 正则表达式获取大括号之间的字符串“{我想要大括号之间的内容}”

我正在尝试,但如果有人可以用他们的专业知识帮助我,那真的会有所帮助......

谢谢斯里...

4

7 回答 7

15

This can certainly be done with regex at least in modern versions of Perl:

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

print join "\n" => @array;

The regex matches a curly brace block that contains either non curly brace characters, or a recursion into itself (matches nested braces)

Edit: the above code works in Perl 5.10+, for earlier versions the recursion is a bit more verbose:

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

my @array = $str =~ /$re/xg;
于 2010-04-23T17:44:25.723 回答
15

使用文本::平衡

于 2010-04-23T17:35:28.220 回答
4

我同意 ysth 使用该Text::Balanced模块的建议。几行字会让你上路。

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;

输出

{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}}}}
        }
于 2010-04-23T18:21:07.683 回答
2

You can always count braces:

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);

This is old, plain Perl style (and ugly, probably).

于 2010-04-23T17:56:17.033 回答
2

我不认为你想在这里使用纯正则表达式(恕我直言,这甚至可能无法使用正则表达式解析)。

相反,构建一个小型解析器,类似于此处显示的内容:http ://www.perlmonks.org/?node_id=308039(请参阅 shotgunefx (Parson) 于 2003 年 11 月 18 日 18:29 UTC 的答案)

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

于 2010-04-23T17:33:28.497 回答
0

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

于 2010-04-23T17:29:51.080 回答
0

正则表达式实际上不适合匹配大括号。根据您想要深入的程度,您可以为Parse::RecDescent编写完整的语法(这比听起来容易得多!)。或者,如果您只想获取块,请搜索打开的“{”标记和关闭的“}”,并计算在任何给定时间打开的数量。

于 2010-04-23T17:34:21.907 回答