我想打印放在()
括号中的文本文件中的句子,而不是一对括号。
例如,对于此文本文件:
blabla(nothing(print me)) nanana (nanan)
blablabla(aaaaaaa(eeee(bbbb(cccc)bbb))aa)
blabla (blabla(hhhhh))
输出应为:
print me
eeee(bbbb(cccc)bbb)
bbbb(cccc)bbb
cccc
hhhhh
这是我到目前为止所做的:
#!/usr/bin/perl -w
open(FILE, "<", $ARGV[0]) or die "file open error";
if ( @ARGV ) #if there are args
{
if ( -f $ARGV[0] ) #if its regular file
{
while(<FILE>)
{
my @array = split('\)',$_);
foreach(@array)
{
if ($_ =~ /.*\((.*)/)
{
print "$1\n";
}
}
}
close(FILE);
}
else{
print "Arg is not a file\n";}
}
else{
print "no args\n";}
我的代码无法将更深层括号中的句子分开。
答案 0 :(得分:2)
假设括号是平衡的:
use strict;
use warnings;
my @a;
while (<DATA>) {
while (/\(([^()]*(?:\(((?1))\)[^()]*(?{push @a, $2}))*+)\)/g){}
}
print join "\n", @a;
__DATA__
blabla(nothing(print me)) nanana (nanan)
blablabla(aaaaaaa(eeee(bbbb(cccc)bb(xxxx)b))aa)
blabla (blabla(hhhhh))
它返回:
print me
cccc
xxxx
bbbb(cccc)bb(xxxx)b
eeee(bbbb(cccc)bb(xxxx)b)
hhhhh
我们的想法是在每次递归后存储捕获组2内容,使用(?{...})
构造在模式中执行代码。
请注意,结果的顺序并不理想,因为最里面的内容首先出现。不幸的是,我没有找到改变结果顺序的方法。
模式细节:
\( # opening bracket level 1
( # open capture group 1
[^()]* # all that is not a bracket
(?:
\( # opening bracket for level 2 (or more when a recursion occurs)
( # capture group 2: to store the result
(?1) # recursion
)
\) # closing bracket for level 2 (or more ...)
[^()]* #
(?{push @a, $2}) # store the capture group 2 content in @a
)*+ # repeat when needed
)
\) # closing bracket level 1
编辑:此模式假定括号是平衡的,但如果不是这种情况,则可能会导致某些字符串出现意外结果的问题。原因是结果在整个模式成功之前存储。
字符串1234 ( 5678 (abcd(efgh)ijkl)
的示例,其中缺少右括号:
1234 ( 5678 (abcd(efgh)ijkl)
# ^ ^---- second attempt succeeds, "efgh" is stored
# '---- first attempt fails, but "efgh", "abcd(efgh)ijkl" are stored
要解决此问题,您可以选择两种默认行为:
"efgh"
:my @a;
my @b;
while (<DATA>) {
while (/\(([^()]*(?:\(((?1))\)[^()]*(?{push @b, $2}))*+)(?:\)|(?{undef @b})(*F))/g) {
push @a, @b;
undef @b;
}
}
\)
替换为(?:\)|$)
。在这种情况下,第一次尝试成功并消耗字符直到字符串结束(换句话说,没有第二次尝试)。结果为"efgh"
和"abcd(efgh)ijkl"
答案 1 :(得分:2)
这可能是最简单的,并且通过双程解决方案可以维护得最多。
初始传递捕获所有第一级括号。第二遍捕获所有括号括起的组,只推进单个字符以匹配每个级别的嵌入式paren组:
#!/usr/bin/env perl
use strict;
use warnings;
use v5.10;
my $data = do { local $/; <DATA> };
my $parens_content_re = qr{
\(
(
(?:
[^()]*+
|
\( (?1) \)
)*
)
\)
}x;
say for map {/(?=$parens_content_re)\(/g} map {/$parens_content_re/g} $data;
__DATA__
blabla(nothing(print me)) nanana (nanan)
blablabla(aaaaaaa(eeee(bbbb(cccc)bbb))aa)
blabla (blabla(hhhhh))
----(----(aaaa(123)bbbb(456)cccc)----)----
输出:
$ perl parens.pl
print me
eeee(bbbb(cccc)bbb)
bbbb(cccc)bbb
cccc
hhhhh
aaaa(123)bbbb(456)cccc
123
456
答案 2 :(得分:2)
此代码的工作原理是递归捕获级别,使用)
的简单正则表达式和split
的{{1}}作为开始表达式。它首先通过剥离两个起始层的嵌套来准备。它适用于显示的示例和其他一些示例。但是,还有其他方法可以嵌套对,但未指定规则。此外,这可能是边缘粗糙。没有涉及任何类型的魔法,调整新案例的代码应该是可行的。
(
打印
blabla(nothing(print me)) nanana (nanan) print me blablabla(aaaaaaa(eeee(bbbb(cccc)bbb))aa) eeee(bbbb(cccc)bbb) bbbb(cccc)bbb cccc blabla (blabla(hhhhh)) hhhhh