如何在 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 中的匹配大括号之间提取字符串?的主要内容,如果未能解决你的问题,请参考以下文章
如果前缀是非常大的文件中的某个字符串,则在括号之间获取/匹配文本[关闭]