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

Posted

技术标签:

【中文标题】如何在 Perl 中的匹配大括号之间提取字符串?【英文标题】:How can I extract a string between matching braces in Perl? 【发布时间】:2011-02-11 15:18:54 【问题描述】:

我的输入文件如下:

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
        "

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

我已经检查了以下链接,但这不适用于我的问题。 Regex to get string between curly braces "I want what's between the curly braces"

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

谢谢 斯里...

【问题讨论】:

【参考方案1】:

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

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

更新 似乎可以使用正则表达式 - 我在 Mastering Regular Expressions 中看到了对匹配嵌套括号的引用(可在 Google 图书上找到,因此如果您不这样做,可以在 Google 上搜索有这本书 - 见第 5 章,“匹配平衡的括号集”部分)

【讨论】:

【参考方案2】:

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

【讨论】:

感谢 zig,您的回复很有帮助。【参考方案3】:

你总是可以数大括号:

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 风格(可能很丑陋)。

【讨论】:

【参考方案4】:

至少在现代版本的 Perl 中,这当然可以用正则表达式来完成:

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

print join "\n" => @array;

正则表达式匹配包含非大括号字符或自身递归的大括号块(匹配嵌套大括号)

编辑:上面的代码在 Perl 5.10+ 中工作,对于早期版本,递归有点冗长:

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

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

【讨论】:

试过这个,但我得到错误序列(?0...)在正则表达式中无法识别;由 标记 @Srilesh => 我发布的代码需要 perl 5.10+,我已经编辑了我的答案以包含一个适用于旧 perls 的版本。 @ysth、@Zaid、@leonbloy 提供的解决方案对我来说效果很好,但@eric 的解决方案性能非常好。我正在对一个 10MB 文件应用递归,与其他文件相比,结果非常快。在这里选择您的答案作为最佳解决方案。非常感谢。【参考方案5】:

我赞同 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,
                               [ subextract_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
        

【讨论】:

根据 ysth 的建议,我使用了 Text::Balanced,但我只得到了第一场比赛。感谢您在这里帮助我,我也需要使用 extract_multiple 子。谢谢你..【参考方案6】:

使用Text::Balanced

【讨论】:

谢谢,这是最好的解决方案! @Srilesh:如果您最喜欢这个答案,请单击答案左侧的勾勒勾号。【参考方案7】:

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

【讨论】:

以上是关于如何在 Perl 中的匹配大括号之间提取字符串?的主要内容,如果未能解决你的问题,请参考以下文章

如果前缀是非常大的文件中的某个字符串,则在括号之间获取/匹配文本[关闭]

PHP中大括号之间的匹配文本

正则表达式提取方括号或大括号之间的文本

正则表达式在非常大的html文件中匹配java中的花括号[重复]

正则表达式(括号)[中括号]{大括号}的区别

正则表达式(括号)[中括号]{大括号}的区别小结