regex - 我可以使用 Perl 正则表达式来匹配平衡的文本吗?

标签 regex perl brackets recursive-regex

我想匹配 Perl 中括号等中的文本。我怎样才能做到这一点?

这是来自 official perlfaq 的问题.我们是 importing the perlfaq to Stack Overflow .

最佳答案

这是official FAQ answer减去任何后续编辑。

您的第一次尝试应该是 Text::Balanced模块,自 Perl 5.8 起就在 Perl 标准库中。它具有多种功能来处理棘手的文本。 Regexp::Common模块还可以通过提供您可以使用的预设模式来提供帮助。

从 Perl 5.10 开始,您可以使用递归模式将平衡文本与正则表达式匹配。在 Perl 5.10 之前,您不得不求助于各种技巧,例如在 (??{}) 中使用 Perl 代码。序列。

这是一个使用递归正则表达式的示例。目标是捕获尖括号内的所有文本,包括嵌套尖括号中的文本。此示例文本有两个“主要”组:一个具有一层嵌套的组和一个具有两层嵌套的组。尖括号中总共有五个组:

I have some <brackets in <nested brackets> > and
<another group <nested once <nested twice> > >
and that's it.

匹配平衡文本的正则表达式使用两个新的(Perl 5.10)正则表达式特性。这些在 perlre 中有介绍这个例子是该文档中一个的修改版本。

一、添加新的所有格+到任何量词找到最长的匹配并且不回溯。这很重要,因为您想通过递归处理任何尖括号,而不是回溯。群[^<>]++找到一个或多个非尖括号而不回溯。

二、新(?PARNO)PARNO 给出的特定捕获组中的子模式.在下面的正则表达式中,第一个捕获组找到(并记住)平衡文本,您需要在第一个缓冲区中使用相同的模式才能通过嵌套文本。这就是递归部分。 (?1)使用外部捕获组中的模式作为正则表达式的独立部分。

把它们放在一起,你有:
#!/usr/local/bin/perl5.10.0

my $string =<<"HERE";
I have some <brackets in <nested brackets> > and
<another group <nested once <nested twice> > >
and that's it.
HERE

my @groups = $string =~ m/
        (                   # start of capture group 1
        <                   # match an opening angle bracket
            (?:
                [^<>]++     # one or more non angle brackets, non backtracking
                  |
                (?1)        # found < or >, so recurse to capture group 1
            )*
        >                   # match a closing angle bracket
        )                   # end of capture group 1
        /xg;

$" = "\n\t";
print "Found:\n\t@groups\n";

输出显示 Perl 找到了两个主要组:
Found:
    <brackets in <nested brackets> >
    <another group <nested once <nested twice> > >

通过一些额外的工作,您可以获得尖括号中的所有组,即使它们也在其他尖括号中。每次获得平衡匹配时,删除其外部分隔符(即您刚刚匹配的分隔符,因此不要再次匹配)并将其添加到要处理的字符串队列中。继续这样做,直到你没有匹配:
#!/usr/local/bin/perl5.10.0

my @queue =<<"HERE";
I have some <brackets in <nested brackets> > and
<another group <nested once <nested twice> > >
and that's it.
HERE

my $regex = qr/
        (                   # start of bracket 1
        <                   # match an opening angle bracket
            (?:
                [^<>]++     # one or more non angle brackets, non backtracking
                  |
                (?1)        # recurse to bracket 1
            )*
        >                   # match a closing angle bracket
        )                   # end of bracket 1
        /x;

$" = "\n\t";

while( @queue )
    {
    my $string = shift @queue;

    my @groups = $string =~ m/$regex/g;
    print "Found:\n\t@groups\n\n" if @groups;

    unshift @queue, map { s/^<//; s/>$//; $_ } @groups;
    }

输出显示所有组。最外层的匹配首先出现,嵌套的匹配稍后出现:
Found:
    <brackets in <nested brackets> >
    <another group <nested once <nested twice> > >

Found:
    <nested brackets>

Found:
    <nested once <nested twice> >

Found:
    <nested twice>

关于regex - 我可以使用 Perl 正则表达式来匹配平衡的文本吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4445674/

相关文章:

如果满足条件,C# 用另一个正则表达式选择替换正则表达式选择

xml - Perl XML::XPath 在文档中添加一堆垃圾

javascript - [\b] 退格正则表达式有什么用?

regex - 使用 Perl 正则表达式解析名称

perl - 构建 perl 模块

javascript - 将对象转换为方括号字符串(不使用 JSON.stringify)

java - 编码性 : Brackets Determine whether a given string of parentheses is properly nested

javascript - ES6 JavaScript 中的括号

regex - bash(首选 sed 或 awk)删除第一个和最后一个实例之间的所有内容

javascript - 正则表达式匹配空格 - 排除多组字符之间的空格