regex - 如何找到嵌套深度超过一个括号 '()' 集的句子?

标签 regex perl

我想从放置在 () 括号中的文本文件中打印比一对括号更深的句子。

例如这个文本文件:

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

我的代码无法分隔放在更深括号中的句子。

最佳答案

假设括号是平衡的:

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

要解决此问题,您可以在两种默认行为之间进行选择:

  • 只接受平衡括号的严格行为。您所需要做的就是将结果存储在一个临时数组中,并在 while 循环中或在缺少右括号时重置该数组。在这种情况下,结果将仅为 "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"

关于regex - 如何找到嵌套深度超过一个括号 '()' 集的句子?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37038927/

相关文章:

regex - Ruby:在字符串之上构建 token 生成器

python - 使用 re.sub() 时无效的组引用

perl - Moose:如何获取对象数组?特质?

perl - 如何使用 perl 安装 dmake?

regex - 查找接口(interface)的网关

php - PHP 中用户提供的正则表达式的清理

perl - 如何在Perl中读取ISO 8859-1(Latin-1)编码的文本

regex - 为什么我的非贪婪 Perl 正则表达式仍然匹配太多?

regex - 在Perl中,如何匹配两个连续的回车符?

javascript - 正则表达式中连字符的这种用法有效吗?